一、实验设计
设计一个电子时钟,要求能够完成时间的显示、复位、设置时间、整点报时的功能。采用VHDL语言写程序,使用Quartus II进行编程,最后在睿智四代AX4010板子上进行实验验证。
二、模块设计
按键消抖模块、时钟分频模块、置数模块、秒分时计数模块、蜂鸣器模块、数码管输出模块。
实现的功能:按键消抖、用户置数、时分秒计时显示、整点报时(n点钟n次)。
三、模块代码
时钟分频模块
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
entity clk_sourse is
port(
clk:in std_logic;
clk2:out std_logic;
clk3:out std_logic
);
end clk_sourse;
architecture a of clk_sourse is
signal clk0:std_logic;
signal clk1:std_logic;
begin
clk2<=clk1;
clk3<=clk0;
process(clk)
variable cnt:integer range 0 to 50000000;
variable cnt1:integer range 0 to 5000;
begin
if(clk'event and clk='1')then
cnt:=cnt+1;
cnt1:=cnt1+1;
if(cnt=50000000)then
clk1<=not clk1;
cnt:=0;
end if;
if(cnt1=5000)then
clk0<=not clk0;
cnt1:=0;
end if;
end if;
end process;
end a;
秒计时模块
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
entity counter1 is
port(
clk:in std_logic;
clr:in std_logic;
key1:in std_logic;
min:out std_logic;
chg0:in std_logic_vector(3 downto 0);
chg1:in std_logic_vector(3 downto 0);
data0:out std_logic_vector(3 downto 0);
data1:out std_logic_vector(3 downto 0)
);
end counter1;
architecture a of counter1 is
signal cnt0:std_logic_vector(3 downto 0):="0000";
signal cnt1:std_logic_vector(3 downto 0):="0000";
begin
process(clk,clr,key1)
begin
if(clr='1' and key1='1')then
if(clk'event and clk='1')then
cnt0<=cnt0+1;
if(cnt0=9)then
cnt0<="0000";
cnt1<=cnt1+1;
end if;
if(cnt1=5 and cnt0=9)then
cnt0<="0000";
cnt1<="0000";
min<='1';
else
min<='0';
end if;
end if;
elsif(clr='0' and key1='1')then
cnt0<="0000";
cnt1<="0000";
elsif(key1='0' and clr='1')then
cnt0<=chg0;
cnt1<=chg1;
else
null;
end if;
data0<=cnt0;
data1<=cnt1;
end process;
end a;
分计时模块
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
entity counter2 is
port(
clk:in std_logic;
clr,key1:in std_logic;--reset
hour:out std_logic;
chg2:in std_logic_vector(3 downto 0);
chg3:in std_logic_vector(3 downto 0);
data2:out std_logic_vector(3 downto 0);
data3:out std_logic_vector(3 downto 0)
);
end counter2;
architecture a of counter2 is
signal cnt0:std_logic_vector(3 downto 0):="0000";--9
signal cnt1:std_logic_vector(3 downto 0):="0000";--1
begin
process(clk,clr,key1)
begin
if(clr='1' and key1='1')then
if(clk'event and clk='1')then
cnt0<=cnt0+1;
if(cnt0=9)then
cnt0<="0000";
cnt1<=cnt1+1;
end if;
if(cnt1=5 and cnt0=9)then
cnt0<="0000";
cnt1<="0000";
hour<='1';
else
hour<='0';
end if;
end if;
elsif(clr='0' and key1='1')then
cnt0<="0000";
cnt1<="0000";
hour<='0';
elsif(key1='0' and clr='1')then
cnt0<=chg2;
cnt1<=chg3;
else
null;
end if;
data2<=cnt0;
data3<=cnt1;
end process;
end a;
时计时模块
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
entity counter3 is
port(
clk:in std_logic;
clr,key1:in std_logic;
chg4,chg5:in std_logic_vector(3 downto 0);
key2:in std_logic;
data4:out std_logic_vector(3 downto 0);
data5:out std_logic_vector(3 downto 0)
);
end counter3;
architecture a of counter3 is
signal cnt0:std_logic_vector(3 downto 0):="0000";--hour gewei
signal cnt1:std_logic_vector(3 downto 0):="0000";--hour shiwei
begin
process(clk,clr,key1,key2)
begin
if(clr='1' and key1='1' and key2='1')then
if(clk'event and clk='1')then
cnt0<=cnt0+1;
if(cnt0=9)then
cnt0<="0000";
cnt1<=cnt1+1;
end if;
if(cnt1=2 and cnt0=3)then
cnt0<="0000";
cnt1<="0000";
end if;
end if;
elsif(clr='0' and key1='1' and key2='1')then
cnt0<="0000";
cnt1<="0000";
elsif(key1='0' and key2='0' and clr='1')then
cnt0<=chg4;
cnt1<=chg5;
else
null;
end if;
data4<=cnt0;--ge
data5<=cnt1;--shi
end process;
end a;
置数模块
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
entity chgclk is
port(
clk:in std_logic;
key1,key2,clr:in std_logic;--add,mode
-- t:out std_logic_vector(1 downto 0);--testport
-- clk2:out std_logic;
cdata0:out std_logic_vector(3 downto 0);
cdata1:out std_logic_vector(3 downto 0);
cdata2:out std_logic_vector(3 downto 0);
cdata3:out std_logic_vector(3 downto 0);
cdata4:out std_logic_vector(3 downto 0);
cdata5:out std_logic_vector(3 downto 0)
);
end chgclk;
architecture a of chgclk is
signal cnt0:std_logic_vector(3 downto 0):="0000";
signal cnt1:std_logic_vector(3 downto 0):="0000";
signal cnt2:std_logic_vector(3 downto 0):="0000";
signal cnt3:std_logic_vector(3 downto 0):="0000";
signal cnt4:std_logic_vector(3 downto 0):="0000";
signal cnt5:std_logic_vector(3 downto 0):="0000";
signal clk1:std_logic:='0';
begin
process(clk)
variable clkcnt:integer range 0 to 1000;--test
begin
if(clk'event and clk='1')then
clkcnt:=clkcnt+1;
if(clkcnt=1000)then--test
clk1<=not clk1;
-- clk2<=clk1;--test
clkcnt:=0;
end if;
end if;
end process;
process(clk1,key1,key2,clr)--change
begin
if(clr='1')then
if(key1='0' and key2='1')then
if(clk1'event and clk1='1')then
cnt0<=cnt0+1;
if(cnt0=9)then
cnt0<="0000";
cnt1<=cnt1+1;
end if;
if(cnt1=5 and cnt0=9)then
cnt0<="0000";
cnt1<="0000";
end if;
end if;
cdata0<=cnt0;
cdata1<=cnt1;
elsif(key1='1' and key2='0')then
if(clk1'event and clk1='1')then
cnt2<=cnt2+1;
if(cnt2=9)then
cnt2<="0000";
cnt3<=cnt3+1;
end if;
if(cnt3=5 and cnt2=9)then
cnt2<="0000";
cnt3<="0000";
end if;
end if;
cdata2<=cnt2;
cdata3<=cnt3;
elsif(key1='0' and key2='0')then
if(clk1'event and clk1='1')then
cnt4<=cnt4+1;
if(cnt4=9)then
cnt4<="0000";
cnt5<=cnt5+1;
end if;
if(cnt5=2 and cnt4=3)then
cnt4<="0000";
cnt5<="0000";
end if;
end if;
cdata4<=cnt4;
cdata5<=cnt5;
else
null;
end if;
else
cnt0<="0000";
cnt1<="0000";
cnt2<="0000";
cnt3<="0000";
cnt4<="0000";
cnt5<="0000";
cdata0<="0000";
cdata1<="0000";
cdata2<="0000";
cdata3<="0000";
cdata4<="0000";
cdata5<="0000";
end if;
end process;
end a;
按键消抖模块
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity unshake is
port(
clk,reset_in,hc_show,next_key,add_key:in std_logic; --按键按下时为0
reset_out,hc_out,next_out,add_out:out std_logic
);
end unshake;
architecture behav of unshake is
begin
process(clk,reset_in)
VARIABLE COUNT1 :INTEGER RANGE 0 TO 20000000;
BEGIN
if reset_in='0' then
if RISING_EDGE(clk) then
if COUNT1<20000000 then COUNT1:=COUNT1+1;
else COUNT1:=COUNT1;
end if;
if COUNT1<=19999999 then reset_out<='1';
else reset_out<='0';
end if;
end if;
else COUNT1:=0;
reset_out<='1';
end if;
end process;
process(clk,hc_show)
VARIABLE COUNT2 :INTEGER RANGE 0 TO 20000000;
BEGIN
if hc_show='0' then
if RISING_EDGE(clk) then
if COUNT2<20000000 then COUNT2:=COUNT2+1;
else COUNT2:=COUNT2;
end if;
if COUNT2<=19999999 then hc_out<='1';
else hc_out<='0';
end if;
end if;
else COUNT2:=0;
hc_out<='1';
end if;
end process;
process(clk,next_key)
VARIABLE COUNT3 :INTEGER RANGE 0 TO 20000000;
BEGIN
if next_key='0' then
if RISING_EDGE(clk) then
if COUNT3<20000000 then COUNT3:=COUNT3+1;
else COUNT3:=COUNT3;
end if;
if COUNT3<=19999999 then next_out<='1';
else next_out<='0';
end if;
end if;
else COUNT3:=0;
next_out<='1';
end if;
end process;
process(clk,add_key)
VARIABLE COUNT4 :INTEGER RANGE 0 TO 20000000;
begin
if add_key='0' then
if RISING_EDGE(clk) then
if COUNT4<20000000 then COUNT4:=COUNT4+1;
else COUNT4:=COUNT4;
end if;
if COUNT4<=19999999 then add_out<='1';
else add_out<='0';
end if;
end if;
else COUNT4:=0;
add_out<='1';
end if;
end process;
end behav;
蜂鸣器模块
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
entity baoshi is
port(
clk:in std_logic;--sec
hourport:in std_logic;
cnt1:in std_logic_vector(3 downto 0);--g
cnt2:in std_logic_vector(3 downto 0);--s
clk1:in std_logic;--clk
bzz:out std_logic
);
end baoshi;
architecture a of baoshi is
signal cnt01:std_logic_vector(3 downto 0):="0000";
signal cnt02:std_logic_vector(3 downto 0):="0000";
signal flag:std_logic:='0';
signal flag1:std_logic:='0';
begin
process(clk,hourport)
begin
if( hourport='1' )then
if(clk'event and clk='1')then
if(flag='0')then
if(NOT(cnt01>=cnt1) or NOT(cnt02>=cnt2))then
cnt01<=cnt01+1;
if(cnt01=9)then
cnt01<="0000";
cnt02<=cnt02+1;
end if;
end if;
end if;
flag<=not flag;
end if;
else
cnt01<="0000";
cnt02<="0000";
end if;
end process;
process(clk1,hourport)
begin
if(hourport='1')then
if(NOT((cnt01>=cnt1)and(cnt02>=cnt2)))then
if(flag='1')then
if(clk1'event and clk1='1')then
if(flag1='1')then
flag1<=not flag1;
bzz<='1';
else
flag1<=not flag1;
bzz<='0';
end if;
end if;
else
bzz<='0';
end if;
end if;
end if;
end process;
end a;
数码管输出模块
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity scan_led is
port(
clk,h_show:in std_logic;
Fin_1:in std_logic_vector(3 downto 0);
Fin_2:in std_logic_vector(3 downto 0);
Fin_3:in std_logic_vector(3 downto 0);
Fin_4:in std_logic_vector(3 downto 0);
Fin_5:in std_logic_vector(3 downto 0);
Fin_6:in std_logic_vector(3 downto 0);
seg:out std_logic_vector(7 downto 0);
data:buffer std_logic_vector(3 downto 0);
scan:out std_logic_vector(3 downto 0)
);
end;
architecture one of scan_led is
signal cnt4:integer range 0 to 3;
begin
process(clk)
begin
if clk'event and clk='1' then
cnt4<=cnt4+1;
end if;
end process;
process(cnt4)
begin
if(h_show='1')then
case cnt4 is
when 0 =>scan<="1110";data<=Fin_3(3 downto 0);
when 1 =>scan<="1101";data<=Fin_4(3 downto 0);
when 2 =>scan<="1011";data<=Fin_1(3 downto 0);
when 3 =>scan<="0111";data<=Fin_2(3 downto 0);
when others=>null;
end case;
else
case cnt4 is
when 0 =>scan<="1110";data<=Fin_6(3 downto 0);
when 1 =>scan<="1101";data<=Fin_5(3 downto 0);
when 2 =>scan<="1111";data<="0000";
when 3 =>scan<="1111";data<="0000";
when others=>null;
end case;
end if;
end process;
process(data)
begin
case data(3 downto 0) is--编码部分
when "0000"=>seg<="00000011";
when "0001"=>seg<="10011111";
when "0010"=>seg<="00100101";
when "0011"=>seg<="00001101";
when "0100"=>seg<="10011001";
when "0101"=>seg<="01001001";
when "0110"=>seg<="01000001";
when "0111"=>seg<="00011111";
when "1000"=>seg<="00000001";
when "1001"=>seg<="00001001";
when others=>null;
end case;
end process;
end;
四、管脚配置
五、结语
由于实验板的不同,在系统的设计上也会有所差异。代码上可以借鉴——至少这套代码是跑得通的。可以借鉴的地方在于蜂鸣器的控制(整点报时功能的实现)、按键消抖实现的原理、译码管控制(数字输出)。然后结合自己的FPGA开发板具体接口可以做出自己的电子钟。
避坑ps:1.按钮输入需要确认有效电平的种类;2.译码输出模块需要配合管脚进行设置,因为管脚绑定可能是不一样的!
这个电子钟还有一些地方不够完善,可能还需要改进。所以,生搬这篇blog的代码是不太建议的。