基于FPGA的数字万年历

一、设计任务

(一)采用 VHDL 语言,利用 Quartus 编程设计一个数字万年历,具有以下功能:

1、时、分、秒的功能设计与调试成功,用数码管显示; 

2、月、日的功能设计与调试成功,用数码管显示; 

3、年(含闰年)的功能设计与调试成功,用数码管轮流显示年、月、日、 时、分、秒; 

4、可手动设置任意日期,包括年、月、日、时、分,按键不超过 4 个; 

5、星期的功能设计与调试成功,用数码管轮流显示年、月、日、时、分、 秒、星期; 

6、能进行闹钟设置以及秒表计时功能; 

7、其他功能(按键消抖、节日提醒); 

(二)利用开发板对设计的电路进行调试检验;

(三)总结电路设计结果。

二、系统设计

图1系统框图

简述万年历设计方案及主要模块:

(一)计数器模块

(二)校时模块

(三)显示及显示方式切换模块

(四)顶层原理图

(五)引脚设定

(六)下载验证

三、模块的实现

(一)计数器模块

1、分、秒计数器

这两个模块都为60进制计数器,源程序的代码如下:

--秒/分 60bcd
--******************************
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
--******************************
ENTITY COUNT_60BCD  IS
    PORT (CLK:IN STD_LOGIC;
            jinwei:OUT STD_LOGIC;
             Q    :OUT STD_LOGIC_VECTOR(7 DOWNTO 0)
            );
END COUNT_60BCD;
--******************************
ARCHITECTURE ABC OF COUNT_60BCD IS
SIGNAL QQ:STD_LOGIC_VECTOR(7 DOWNTO 0);
BEGIN 
PROCESS (CLK)
BEGIN 
    IF CLK'EVENT AND CLK='1' THEN 
        IF QQ>="01011001" THEN QQ<="00000000";jinwei<='1';
        ELSIF QQ(3 DOWNTO 0)>="1001" THEN
        QQ(3 DOWNTO 0)<="0000";
        QQ(7 DOWNTO 4)<=QQ(7 DOWNTO 4)+1;
        jinwei<='0';
        ELSE QQ<=QQ+1;
        jinwei<='0';
    END IF;
    END IF;
END PROCESS;
Q<=QQ;
END ABC;

CLK表示时钟脉冲信号,CLR表示重置(清零),jinwei表示进位,Q表示输出。

当CLR设置为1表示清零,Q输出都为零。

当CLR设置为0表示未进行重置,当秒/分计数器计数到59时,等待CLK信号下一个脉冲上升沿到来时,输出jinwei产生一个输出脉冲,同时秒/分计数器再次从0开始计数(1分钟=60秒/1小时=60分钟)。

2、时计数器

模块为24进制计数器,源程序的代码如下图:

--时 24bcd
--******************************
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
--******************************
ENTITY hour_24bcd  IS
    PORT (CLK:IN STD_LOGIC;
            jinwei:OUT STD_LOGIC;
                Q    :OUT STD_LOGIC_VECTOR(7 DOWNTO 0)
            );
END hour_24bcd;
--******************************
ARCHITECTURE ABC OF hour_24bcd IS
SIGNAL QQ:STD_LOGIC_VECTOR(7 DOWNTO 0);
BEGIN 
PROCESS (CLK)
BEGIN 
    IF CLK'EVENT AND CLK='1' THEN 
        IF QQ>="00100011" THEN     --
        QQ<="00000000";jinwei<='1';--进位
        ELSIF QQ(3 DOWNTO 0)>="1001" THEN--bcd进位    
        QQ(3 DOWNTO 0)<="0000";
        QQ(7 DOWNTO 4)<=QQ(7 DOWNTO 4)+1;
        jinwei<='0';
        ELSE QQ<=QQ+1;jinwei<='0';
    END IF;    
    END IF;
END PROCESS;
Q<=QQ;
END ABC;

 

CLK表示时钟脉冲信号,CLR表示重置(清零),jinwei表示进位,Q表示输出。

当CLR设置为1表示清零,Q输出都为零。

当CLR设置为0表示未进行重置,当时计数器计数到23时,等待CLK信号下一个脉冲上升沿到来时,进位输出jinwei产生一个输出脉冲,同时时计数器再次从0开始计数(1天=24小时)。

3、日计数器

日计数器进制设定有四种不同的情况。若该月为大月(1,3,5,7,8,10,12)日计数器到31时才产生进位信号。若该月为小月(4,6,9,11)日计数器计数到30时就产生进位信号。若该月为闰年的2月,日计数器计数到29时就产生进位信号。若该月为平年的2月,日计数器计数到28时就产生进位信号。所以,日计数器需要输入判断信号is_leap_year,如果是闰年即is_leap_year为1则2月有29天,否则2月有28天。

日计数器的源程序代码如下图:

--日计数器 31bcd
--******************************
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.NUMERIC_STD.ALL;
--******************************
ENTITY day_31  IS
    PORT (clk :IN STD_LOGIC;              --使能信号/重置信号
            yue:in std_logic_vector(7 downto 0);--当前月份
            is_leap_year:in std_logic;--闰年判断
            jinwei:OUT STD_LOGIC;--满一个月则需要进位
            Q    :OUT STD_LOGIC_VECTOR(7 DOWNTO 0)--当前日期
            );
END day_31;
--******************************
ARCHITECTURE ABC OF day_31 IS
SIGNAL QQ:STD_LOGIC_VECTOR(7 DOWNTO 0);
signal days_in_month :std_logic_vector(7 downto 0);
begin
    process(yue, is_leap_year)           --月份内的天数判断
    begin
            case yue is
                when "00000001" | "00000011" |"00000101" | "00000111" | "00001000" | "00010000" | "00010010" =>--1 | 3 | 5 | 7 | 8 | 10 | 12
                    days_in_month <="00110001";--31                                                      
                when "00000100" | "00000110" | "00001001" | "00010001" => --4 | 6 | 9 | 11                                 
                    days_in_month <="00110000";--30
                when "00000010" =>            --2月进行闰年判断
                   if is_leap_year = '1' then
                    days_in_month <= "00101001";--闰年的二月29天
                else
                    days_in_month <= "00101000";--非闰年28天
                end if;
            when others =>days_in_month <= "00110001";--其他情况设置为31天
        end case;
    end process;
    -- 日期计数逻辑
    process(clk,days_in_month)
    begin
        if clk'event and clk='1' then
          IF QQ>=days_in_month THEN QQ<="00000001";jinwei<='1';--满一个月进位
               ELSIF QQ(3 DOWNTO 0)>="1001" THEN           --由于bcd,个位慢9进位
                    QQ(3 DOWNTO 0)<="0000";
                    QQ(7 DOWNTO 4)<=QQ(7 DOWNTO 4)+1;
                    jinwei<='0';
                ELSE QQ<=QQ+1; 
                    jinwei<='0'; 
                end if;
            end if;
    end process;
     Q<=QQ;
END ABC;

CLK表示时钟脉冲信号,is_leap_year判断闰年,rst重置,yue表示月,jinwei表示进位,Q表示输出。

当rst设置为0表示未进行重置,is_leap_year为0即不是闰年,yue=“00000010”即2月,Q输出到28时,输出jinwei产生一个进位输出脉冲,同时日计数器再次从1开始计数。

当rst设置为1表示重置(清零),Q输出清零同时日计数器再次从1开始计数。

4、月计数器

该模块为十二进制计数器,代码如下:

--月 12bcd
--******************************
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
--******************************
ENTITY COUNT_12  IS
    PORT (CLK:IN STD_LOGIC;
            jinwei:OUT STD_LOGIC;
            Q       :OUT STD_LOGIC_VECTOR(7 DOWNTO 0)
            );
END COUNT_12;
--******************************
ARCHITECTURE ABC OF COUNT_12 IS
SIGNAL QQ:STD_LOGIC_VECTOR(7 DOWNTO 0);

BEGIN 
    PROCESS(CLK)
    BEGIN 
   IF CLK'EVENT AND CLK='1' THEN 
        IF QQ>="00010010" THEN   --有十二月,所以到十二进位
        QQ<="00000000";jinwei<='1';--进位
        ELSIF QQ(3 DOWNTO 0)>="1001" THEN--bcd进位    
        QQ(3 DOWNTO 0)<="0000";
        QQ(7 DOWNTO 4)<="0001";
        jinwei<='0';
        ELSE QQ<=QQ+1;jinwei<='0';
    END IF;    
    END IF;
END PROCESS;
Q<=QQ;
END ABC;

CLK表示时钟脉冲信号,CLR表示重置(清零),jinwei表示进位,Q表示输出。

当CLR设置为1表示清零,Q输出都为零。当CLR设置为0表示未进行重置,当月计数器计数到11时,等待CLK信号下一个脉冲上升沿到来时,输出jinwei产生一个输出脉冲,同时秒/分计数器再次从0开始计数(1年=12个月)。

5、年计数器

该模块由两部分组成,一个代表年的低位(后两位),另一个表示年的高位(前两位),代码相同,都是100进制,如下:

--年 100进制计数器
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
--********************************
entity COUNT_100BCD is
    port (
        CLK : in std_logic;
        Q       : out std_logic_vector(7 downto 0);
          TCN            :out std_logic
    );
end COUNT_100BCD;
--***************************************
architecture abc of COUNT_100BCD is
    signal QQ : std_logic_vector(7 downto 0):="00100000";
begin

    process(CLK) 
    begin
        if CLK'EVENT AND CLK='1' then -- 上升沿触发
                if QQ >="10011001" then 
                QQ<="00000000" ; TCN<='1';
                ELSIF QQ(3 DOWNTO 0) >="1001" THEN
                QQ(3 downto 0) <="0000"; -- 将低四位清零
                QQ(7 downto 4) <=QQ(7 downto 4)+1; -- 高四位加一
                     TCN<='0';
            else 
                QQ <=QQ+1; -- 否则正常加一
                     TCN<='0';
            end if;
        end if;
    end process;
    Q <= QQ; -- 输出信号
end abc;

CLK表示时钟脉冲信号,Q表示输出,TCN为进位。Q输出到99时,输出TCN产生一个进位输出脉冲,同时年计数器再次从0开始计数。

6、闰年判断

代码如下:

--判断当前年份是否是闰年
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
--********************************
entity RUNNIAN is
    Port (
        NIAN : in STD_LOGIC_VECTOR(15 downto 0);  -- 输入的BCD数,前8位为年份的十进制表示(假设范围足够处理所需年份)
        RUN    : out STD_LOGIC                     -- 输出‘1’表示闰年
    );
end RUNNIAN;
--*************************************
architecture Behavioral of RUNNIAN is
begin
    process(NIAN)
        variable yearDec : integer;  -- 用于存储转换后的十进制年份
    begin
        -- 将BCD编码的年份转换为十进制
            yearDec := CONV_INTEGER(NIAN(15 downto 12)) * 1000 +
                          CONV_INTEGER(NIAN(11 downto 8)) * 100 +
                          CONV_INTEGER(NIAN(7 downto 4)) * 10 +
                          CONV_INTEGER(NIAN(3 downto 0));        
        -- 判断是否为闰年
        if (yearDec mod 4 = 0 and yearDec mod 100 /= 0) or (yearDec mod 400 = 0) then
            RUN <= '1';
        else
            RUN <= '0';
        end if;
    end process;
end Behavioral;

NIAN表示年RUN表示闰年例如:NIAN“0010000000100100”=2024是闰年即RUN=1,

NIAN=“0010000000100011”不是闰年

(二)校时模块

1、调整时间

调整时间源程序代码,如下 :

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

ENTITY MENU_TZ IS
    PORT( CLK, RESET : IN std_logic;
          X : OUT std_logic;
          Y : OUT std_logic_vector( 5 downto 0)
    );
END MENU_TZ;

ARCHITECTURE abc OF MENU_TZ IS
signal Q1 :std_logic_vector( 2 downto 0):="000";
SIGNAL Y1 :STD_LOGIC_VECTOR(5 DOWNTO 0) :="111111";
SIGNAL X1 :STD_LOGIC;
BEGIN
    PROCESS (CLK, RESET)
BEGIN
    IF RESET = '1' THEN     --清零
        Q1 <= "000";
        Y1 <= "111111";
    ELSIF CLK'EVENT AND CLK='1' THEN -- 确保在时钟上升沿检查复位信号
                CASE Q1 IS
                WHEN "000" => Q1 <= "001"; Y1 <= "111111";
                WHEN "001" => Q1 <= "010"; Y1 <= "111110";--年高位
                WHEN "010" => Q1 <= "011"; Y1 <= "111101";--年低位
                WHEN "011" => Q1 <= "100"; Y1 <= "111011";--月 
                WHEN "100" => Q1 <= "101"; Y1 <= "110111";--天
                WHEN "101" => Q1 <= "110"; Y1 <= "101111";--时
                WHEN "110" => Q1 <= "000"; Y1 <= "011111";--分
                WHEN OTHERS => Q1 <= "000"; Y1 <= "111111";
            END CASE;
                END IF;
END PROCESS;
Y<=Y1;
end abc;

CLK表示时钟脉冲信号,RESET表示重置,Y调整时间

2、二选一数据选择器

选择前一个计数器进位的脉冲或者是手动调整时间的脉冲,程序如下:

--切换计数器时钟信号,实现正常计时或调整时间
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity MUX2 is
    Port (
        X1, X2 : in  STD_LOGIC;  -- 两个数据输入
        A : in  STD_LOGIC;  -- 选择信号,'0'选择X1,'1'选择X2
        Y : out STD_LOGIC  -- 输出信号,选择的输入数据
    );
end MUX2;

architecture Behavioral of MUX2 is
begin
    Y <= X1 when A = '0' else X2;  -- ‘0’>X1;'1'>X2
end Behavioral;

(三)

1、共阴极七位数码管

--8421码的共阴极七位数码管的显示译码器
--******************************
LIBRARY IEEE;
USE IEEE. STD_LOGIC_1164.ALL;
USE IEEE. STD_LOGIC_ARITH.ALL;
USE IEEE. STD_LOGIC_UNSIGNED. ALL;
--********************************
entity seven_segment_decoder is  
    Port ( CLK : IN STD_LOGIC;
              A,B,C,D,E,F : in STD_LOGIC_VECTOR (3 downto 0); 
              LED_SEG : OUT STD_LOGIC_VECTOR(6 DOWNTO 0);    --段控制信号输出
              LED_SCAN : OUT STD_LOGIC_VECTOR(5 DOWNTO 0) --位控制信号输出  
);
              end seven_segment_decoder;  
--*******************************  
architecture ABC of seven_segment_decoder is  
signal F1,F2,F3,F4,F5,F6 : std_logic_vector(6 downto 0); 
SIGNAL CNT_4 : STD_LOGIC_VECTOR(2 DOWNTO 0); 
BEGIN
PROCESS(CLK)
BEGIN
IF CLK'EVENT AND CLK = '1' THEN
        IF CNT_4 /= "101" THEN
            CNT_4 <= CNT_4 + 1;
          else 
                CNT_4 <="000";
        END IF;

    END IF;
END PROCESS;
--***********************************
PROCESS(CNT_4)
BEGIN

CASE CNT_4 IS
WHEN "000" =>LED_SEG<=F1; LED_SCAN<="111110";
WHEN "001" =>LED_SEG<=F2; LED_SCAN<="111101";
WHEN "010" =>LED_SEG<=F3; LED_SCAN<="111011";
WHEN "011" =>LED_SEG<=F4; LED_SCAN<="110111";
WHEN "100" =>LED_SEG<=F5; LED_SCAN<="101111";
WHEN "101" =>LED_SEG<=F6; LED_SCAN<="011111";
WHEN OTHERS=>NULL;
END CASE;

END PROCESS;
--***********************************
    process(A,B,C,D,E,F)  
      begin
        case A is  
            WHEN "0000"=>F1<="0111111";
                WHEN "0001"=>F1<="0000110";
                WHEN "0010"=>F1<="1011011";
                WHEN "0011"=>F1<="1001111";
                WHEN "0100"=>F1<="1100110";
                WHEN "0101"=>F1<="1101101";
                WHEN "0110"=>F1<="1111101";
                WHEN "0111"=>F1<="0000111";
                WHEN "1000"=>F1<="1111111";
                WHEN "1001"=>F1<="1101111"; 
            when others => F1 <= "0000000"; -- 关闭所有段(全亮,如果是共阳极则需要取反)  
        end case;


        case B is  
              WHEN "0000"=>F2<="0111111";
                WHEN "0001"=>F2<="0000110";
                WHEN "0010"=>F2<="1011011";
                WHEN "0011"=>F2<="1001111";
                WHEN "0100"=>F2<="1100110";
                WHEN "0101"=>F2<="1101101";
                WHEN "0110"=>F2<="1111101";
                WHEN "0111"=>F2<="0000111";
                WHEN "1000"=>F2<="1111111";
                WHEN "1001"=>F2<="1101111"; 
            when others => F2 <= "0000000"; -- 关闭所有段(全亮,如果是共阳极则需要取反)  
        end case;
 
        case C is  
              WHEN "0000"=>F3<="0111111";
                WHEN "0001"=>F3<="0000110";
                WHEN "0010"=>F3<="1011011";
                WHEN "0011"=>F3<="1001111";
                WHEN "0100"=>F3<="1100110";
                WHEN "0101"=>F3<="1101101";
                WHEN "0110"=>F3<="1111101";
                WHEN "0111"=>F3<="0000111";
                WHEN "1000"=>F3<="1111111";
                WHEN "1001"=>F3<="1101111"; 
            when others => F3 <= "0000000"; -- 关闭所有段(全亮,如果是共阳极则需要取反)  
        end case;
 
        case D is  
              WHEN "0000"=>F4<="0111111";
                WHEN "0001"=>F4<="0000110";
                WHEN "0010"=>F4<="1011011";
                WHEN "0011"=>F4<="1001111";
                WHEN "0100"=>F4<="1100110";
                WHEN "0101"=>F4<="1101101";
                WHEN "0110"=>F4<="1111101";
                WHEN "0111"=>F4<="0000111";
                WHEN "1000"=>F4<="1111111";
                WHEN "1001"=>F4<="1101111"; 
            when others => F4 <= "0000000"; -- 关闭所有段(全亮,如果是共阳极则需要取反)  
        end case;
  
        case E is  
              WHEN "0000"=>F5<="0111111";
                WHEN "0001"=>F5<="0000110";
                WHEN "0010"=>F5<="1011011";
                WHEN "0011"=>F5<="1001111";
                WHEN "0100"=>F5<="1100110";
                WHEN "0101"=>F5<="1101101";
                WHEN "0110"=>F5<="1111101";
                WHEN "0111"=>F5<="0000111";
                WHEN "1000"=>F5<="1111111";
                WHEN "1001"=>F5<="1101111"; 
            when others => F5 <= "0000000"; -- 关闭所有段(全亮,如果是共阳极则需要取反)  
        end case;
   
        case F is  
              WHEN "0000"=>F6<="0111111";
                WHEN "0001"=>F6<="0000110";
                WHEN "0010"=>F6<="1011011";
                WHEN "0011"=>F6<="1001111";
                WHEN "0100"=>F6<="1100110";
                WHEN "0101"=>F6<="1101101";
                WHEN "0110"=>F6<="1111101";
                WHEN "0111"=>F6<="0000111";
                WHEN "1000"=>F6<="1111111";
                WHEN "1001"=>F6<="1101111";
            when others => F6 <= "0000000"; -- 关闭所有段(全亮,如果是共阳极则需要取反)  
        end case;
    end process;  
end ABC;

2、万年历所有的显示

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

ENTITY WNL IS 
PORT (
    CLK : IN STD_LOGIC; 
    QM : IN STD_LOGIC_VECTOR(7 DOWNTO 0);--秒
    QF : IN STD_LOGIC_VECTOR(7 DOWNTO 0);--分
    QS : IN STD_LOGIC_VECTOR(7 DOWNTO 0);--时
    QR : IN STD_LOGIC_VECTOR(7 DOWNTO 0);--日
    QY : IN STD_LOGIC_VECTOR(7 DOWNTO 0);--月
    QN : IN STD_LOGIC_VECTOR(15 DOWNTO 0); -- 年 注意QN为16位向量
    QW : IN STD_LOGIC_VECTOR(7 DOWNTO 0);--星期
     QMB:IN STD_LOGIC_VECTOR(7 DOWNTO 0);--秒表
     QMBF:IN STD_LOGIC_VECTOR(7 DOWNTO 0);--秒表分钟
    DATA_1 : OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
    DATA_2 : OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
    DATA_3 : OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
    DATA_4 : OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
    DATA_5 : OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
    DATA_6 : OUT STD_LOGIC_VECTOR(3 DOWNTO 0)
);
END;

ARCHITECTURE ONE OF WNL IS

    SIGNAL cnt : INTEGER RANGE 0 TO 3 := 0; -- 用于计数状态切换
BEGIN


    PROCESS(CLK)
    BEGIN
        IF CLK'EVENT AND CLK='1' THEN
            cnt <= cnt + 1;
                IF cnt = 3 THEN -- 每三个时钟周期切换一次状态
                cnt <= 0;
            END IF;
        END IF;
    END PROCESS;
     PROCESS(cnt)
     begin     
        case cnt is
        when 0 =>
        DATA_1 <= QM(3 DOWNTO 0);
      DATA_2 <= QM(7 DOWNTO 4);
      DATA_3 <= QF(3 DOWNTO 0);
      DATA_4 <= QF(7 DOWNTO 4);
      DATA_5 <= QS(3 DOWNTO 0);
      DATA_6 <= QS(7 DOWNTO 4);
        WHEN 1 =>
        DATA_1 <= QW(3 DOWNTO 0);
      DATA_2 <= "0000";
      DATA_3 <= QR(3 DOWNTO 0);
      DATA_4 <= QR(7 DOWNTO 4);
        DATA_5 <= QY(3 DOWNTO 0);
      DATA_6 <= QY(7 DOWNTO 4);
        WHEN 2 =>
        DATA_4 <= QN(15 DOWNTO 12);
      DATA_3 <= QN(11 DOWNTO 8);
      DATA_2 <= QN(7 DOWNTO 4);
      DATA_1 <= QN(3 DOWNTO 0);
        DATA_5 <= "0000";
      DATA_6 <= "0000";
        WHEN 3 =>
        DATA_1 <= QMB(3 DOWNTO 0);
      DATA_2 <= QMB(7 DOWNTO 4);
      DATA_3 <= QMBF(3 DOWNTO 0);
      DATA_4 <= QMBF(7 DOWNTO 4);
      DATA_5 <= "0000";
      DATA_6 <= "0000";
        END CASE;
        
    END PROCESS;
END ARCHITECTURE ONE;

(四)其他功能

1、秒表

-- 功能    :    秒表计时
--*******************************************************************
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
--*******************************************************************
entity MB is
    port (
--         STOP   : in std_logic;
          STAR   : in std_logic;
         CLR    : in std_logic;
        CLK    : in std_logic;
          TCN    : out std_logic;--进位
          CLR2   : out std_logic;--清零
        Q      : out std_logic_vector(7 downto 0)
    );
end MB;
--*******************************************************************
architecture abc of MB is
    signal QQ : std_logic_vector(7 downto 0);
     signal c2 : std_logic;
begin

    process(CLK,CLR,STOP,STAR) 
    begin
     IF STAR='1'THEN 
         IF CLR='1'THEN QQ<="00000000";c2<='1';
        ELSif STOP='0'THEN
              IF CLK'EVENT AND CLK='1' then
            IF QQ >="01011001" 
                then QQ<="00000000";TCN<='1';     -- 计数到59时
                ELSIF QQ(3 DOWNTO 0) >="1001" THEN
                QQ(3 downto 0) <="0000"; -- 将低四位清零
                QQ(7 downto 4) <=QQ(7 downto 4)+1; -- 高四位加一
            else 
                QQ <=QQ+1; -- 否则正常加一
                     TCN<='0';
                     END IF;
            end IF;
        end if;
          END IF;
    end process;
     CLR2 <= c2;
    Q <= QQ; -- 输出信号
end abc;

2、节日 

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

ENTITY JIERI IS
PORT (
    EN : IN  STD_LOGIC;      
    Y_IN : IN  STD_LOGIC_VECTOR(7 DOWNTO 0);
    R_IN : IN  STD_LOGIC_VECTOR(7 DOWNTO 0);
    TIME_ON : OUT STD_LOGIC            -- 节日结果输出,当达到设定时间后输出高电平,且一直保持,直到关上闹钟开关
);
END JIERI;

ARCHITECTURE Behavioral OF JIERI IS
BEGIN
    PROCESS (EN, Y_IN, R_IN)
    BEGIN
        IF EN = '1' THEN  -- 当节日开关打开时
            IF ((R_IN = "00101001") AND (Y_IN = "00000010")) OR
               ((R_IN = "00100101") AND (Y_IN = "00010010")) OR
               ((R_IN = "00000001") AND (Y_IN = "00000110")) THEN
                -- 检查是否为特定的时间点
                TIME_ON <= '0';  -- 如果是设定的时间点,则输出高电平,表示触发
            ELSE
                TIME_ON <= '1';  -- 不是设定时间点,输出低电平
            END IF;
        ELSE
            TIME_ON <= '1';  --关闭时,始终输出低电平
        END IF;
    END PROCESS;
END Behavioral;

3、闹钟

 

--闹钟
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

ENTITY NAOZHONG IS
PORT (
    EN : IN  STD_LOGIC;      -- EN相当于闹钟开关,高电平打开
    S_IN : IN  STD_LOGIC_VECTOR(7 DOWNTO 0);
    F_IN : IN  STD_LOGIC_VECTOR(7 DOWNTO 0);
    TIME_ON : OUT STD_LOGIC            -- 闹钟结果输出,当达到设定时间后输出高电平,且一直保持,直到关上闹钟开关
);
END NAOZHONG;

ARCHITECTURE Behavioral OF NAOZHONG IS
BEGIN
    PROCESS (EN, S_IN, F_IN)
    BEGIN
        IF EN = '1' THEN  -- 当闹钟开关打开时
            IF ((S_IN = "00100011") AND (F_IN = "01011001")) OR
               ((S_IN = "00100001") AND (F_IN = "00010010")) OR
               ((S_IN = "00000001") AND (F_IN = "00000110")) THEN
                -- 检查是否为特定的时间点
                TIME_ON <= '1';  -- 如果是设定的时间点,则输出高电平,表示闹钟触发
            ELSE
                TIME_ON <= '0';  -- 不是设定时间点,输出低电平
            END IF;
        ELSE
            TIME_ON <= '0';  -- 闹钟关闭时,始终输出低电平
        END IF;
    END PROCESS;
END Behavioral;

四、总体架构

 

以上就是所有,有其他问题可以私信或者在评论区发,我看到了就会回,演示视频在b站【基于fpga的数字万年历成果展示-哔哩哔哩】 https://b23.tv/BTH5XRh

  • 12
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值