1.设计概述
万年历的功能有显示年、月、日、星期。其中,年月日均需可调,星期随万年历不用设置。数码管只有八位,所以不够显示,还需设计一个切换按钮,切换显示星期,显示在最左边的一个数码管。
2.总体模块划分
1)计时模块
1.日计时模块
计时模块中,日计数器模块是比较特别的,因为它的进制设定有四种不同的情况,若该月为大月(1、3、5、7、8、10、12),日计数器计数至31时才产生进位信号。若为该月小月(4、6、9、11),日计数器计数至30时就产生进位信号。若该月为闰年的2月,日计数器计数至29时就产生进位信号。若该月为平年的2月份,日计数器计数至28时就产生进位信号。所以,在日计数器中需要输入判断信号,该判断信号可用2位2进制表示, 若判断信号为00,则日计数器为28进制计数器;若判断信号为01,则日计数器为29进制计数器;若判断信号为10,则日计数器为30进制计数器;若判断信号为11,则日计数器为31进制计数器。该判断信号judge可从月计数器的判断信号的输出judge引入。
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity day is
port(clk:in std_logic;
d1,d2:out std_logic_vector(3 downto 0);
judge:in std_logic_vector(1 downto 0);
cout:out std_logic);
end day;
architecture one of day is
signal q11,q22:std_logic_vector(3 downto 0);
signal panduan:std_logic_vector(1 downto 0);
begin
process(clk,judge)
begin
if clk'event and clk='1' then
q11<=q11+1;
if q11=9 then q11<=(others=>'0');
q22<=q22+1;
end if;
panduan<=judge;
case panduan is
when "00"=>if q22=2 and q11=8
then q22<="0000";q11<="0001";cout<='1';
else cout<='0';
end if;
when "01"=>if q22=2 and q11=9
then q22<="0000";q11<="0001";cout<='1';
else cout<='0';
end if;
when "10"=>if q22=3 and q11=0
then q22<="0000";q11<="0001";cout<='1';
else cout<='0';
end if;
when "11"=>if q22=3 and q11=1
then q22<="0000";q11<="0001";cout<='1';
else cout<='0';
end if;
when others=>null;
end case;
end if;
end process;
d1<=q11;d2<=q22;
end;
2.月计时模块
月计数器为12进制计数器,但需要为日计数器的进制提供判断信号, 所以该模块需要有判断信号的输出。此外,由于闰年的2月和平年的2月,判断信号输出不同,所以该模块需要从年计数模块引入闰年的判断信号。最终,其必须达到如下设计要求:若月份是大月,则该信号judge输出00,若月份是小月,则该信号judge输出01,若月份是平年的2月,则该信号judge输出10, 若月份是闰年的2月,则该信号judge输出11。
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY month IS
port(clk:in std_logic;
run:in std_logic;
c:out std_logic;
judge:out std_logic_vector(1 downto 0);
q1,q2:out std_logic_vector(3 downto 0));
END ENTITY month;
ARCHITECTURE behave of month IS
SIGNAL qq1,qq2:STD_LOGIC_VECTOR(3 DOWNTO 0);
SIGNAL q3:STD_LOGIC_VECTOR(7 DOWNTO 0);
BEGIN
PROCESS(clk)
BEGIN
if clk'event and clk='1' then
qq1<=qq1+'1';
if qq1=9 then
qq2<=qq2+'1';qq1<="0000";
end if;
if qq2=1 and qq1=2 then
qq1<="0001";qq2<="0000";c<='1';
else c<='0';
end if;
end if;
q3<=qq2&qq1;
case q3 is
when "00000001"=>judge<="11"; --january
when "00000010"=>if run='1'then judge<="01"; else judge<="00"; end if; --february
when "00000011"=>judge<="11"; --march
when "00000100"=>judge<="10"; --april
when "00000101"=>judge<="11"; --may
when "00000110"=>judge<="10"; --june
when "00000111"=>judge<="11"; --july
when "00001000"=>judge<="11"; --august
when "00001001"=>judge<="10"; --september
when "00010000"=>judge<="11"; --october
when "00010001"=>judge<="10"; --november
when "00010010"=>judge<="11"; --december
when others=>null;
end case;
end process;
q1<=qq1;q2<=qq2;
end architecture behave;
3.年计时模块
年计数器为100进制计数器,同时在计数器中需要判断该年是否为闰年或平年。
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY year IS
PORT(clk:IN STD_LOGIC;
y1,y2:OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
run:OUT STD_LOGIC;
c:out std_logic);
END ENTITY year;
ARCHITECTURE behave OF year IS
SIGNAL q1,q2,q3:STD_LOGIC_VECTOR(3 DOWNTO 0);
BEGIN
PROCESS(clk)
BEGIN
if clk'event and clk='1'then
q1<=q1+1;
if q1=9 then
q1<="0000";q2<=q2+1;
end if;
if q2=9 and q1=9 then
q2<="0000";q1<="0000";c<='1';
else c<='0';
end if;
end if;
end process;
PROCESS(clk)
BEGIN
if clk'event and clk='1'then
q3<=q3+'1';
if q3=3 then
q3<="0000";run<='1';
else run<='0';
end if;
end if;
y1<=q1;
y2<=q2;
end process;
end architecture behave;
2)校时模块
校时模块的主要功能是校对时间,本设计中校时功能主要通过按键K1,K2来实现。该模块使得系统具有四种工作模式:1)正常计时;2)校日;3)校月;4)校年。
在本设计中,通过按键K1来选择工作方式,K2来改变各计数器的值,根据所按按键次数不同进入不同的工作模式。设置了2位二进制向量来表示K1的值,”00”表示保持计时状态,”01”表示选择校日,”10”表示选择校月,”11”表示校年。并且设置了3个LED指示灯来表示4种工作方式。
例如:在正常的计时工作方式中,3个LED指示灯熄灭,校日时,LED1灯发亮;以此类推,在校年时LED3灯发亮。
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY timing IS
PORT(wi,di,mi,yi:IN STD_LOGIC;
k1,k2:IN STD_LOGIC;
wo,do,mo,yo:OUT STD_LOGIC;
led1,led2,led3,led4:OUT STD_LOGIC);
END ENTITY timing;
ARCHITECTURE behave OF timing IS
SIGNAL a:STD_LOGIC_VECTOR(2 DOWNTO 0);
BEGIN
PROCESS(k1,k2)
BEGIN
if k1'event and k1='1' then
a<=a+1;
if a=4 then
a<="000";
end if;
end if;
case a is
when"000"=>wo<=wi;do<=di;mo<=mi;yo<=yi;
led1<='0';led2<='0';led3<='0';led4<='0';
when"001"=>wo<=k2;do<='0';mo<='0';yo<='0';
led1<='1';led2<='0';led3<='0';led4<='0';
when"010"=>wo<='0';do<=k2;mo<='0';yo<='0';
led1<='0';led2<='1';led3<='0';led4<='0';
when"011"=>wo<='0';do<='0';mo<=k2;yo<='0';
led1<='0';led2<='0';led3<='1';led4<='0';
when"100"=>wo<='0';do<='0';mo<='0';yo<=k2;
led1<='0';led2<='0';led3<='0';led4<='1';
when others=>null;
end case;
end process;
end architecture behave;
3)显示及显示模块
显示与显示方式切换模块主要为了实现显示功能及显示方式切换功能。万年历不仅要显示年月日,而且要显示星期,显示功能由K3按键来实现。当不按K3按键时,显示方式为年月日显示,led输出低电平,作为显示方式的指示信号。当按下K3按键后,led输出为高电平,显示方式为星期。若再次按K3按键,又进入年月日显示模式,从而实现利用K3按键循环切换显示方式的功能。此外,还需设置另一个小模块与显示模块相连接,即数码管的连接模块,这一部分需要花费一些时间。
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY display IS
PORT(d1,d2,m1,m2,y1,y2,w:IN STD_LOGIC_VECTOR(3 DOWNTO 0);
K3:IN STD_LOGIC;
led:OUT STD_LOGIC;
q1,q2,q3,q4:OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
q5,q6,q7,q8:OUT STD_LOGIC_VECTOR(3 DOWNTO 0));
END ENTITY display;
ARCHITECTURE behave OF display IS
SIGNAL a:STD_LOGIC_VECTOR(1 DOWNTO 0);
BEGIN
PROCESS(K3)
BEGIN
if K3'event and K3='1'then
a<=a+'1';
if a=1 then
a<="00";
end if;
end if;
case a is
when"00"=>q8<=y1;q7<=y2;q6<="1111";q5<=m1;q4<=m2;
q3<="1111";q2<=d1;q1<=d2;led<='0';
when"01"=>q8<=w;q7<="1110";q6<="1110";q5<="1110";q4<="1110";
q3<="1110";q2<="1110";q1<="1110";led<='1';
when others=>null;
end case;
end process;
end architecture behave;