目录
引言
最近快期末考试周了,课设任务也随之而来。这个学期要完成FPGA的课程设计,题目有三个,为了弥补模电焊板子课设的遗憾这次我又选择了数字时钟的任务。经过两天硬肝,各方面找资料终于在上个礼拜六晚上两点钟完成了课设。今天休息而且好久没写博客就写篇文章总结一下吧!
课设题目
可以看到,只需要完成正常的时间显示以及调时,分以及在特定的时间蜂鸣器发出响声即可。
时,分,秒模块
话不多说,直接先上代码
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity second is
port (clk,clr:in std_logic;
sec1,sec0:out std_logic_vector(3 downto 0);
co:out std_logic);
end second;
architecture sec of second is
SIGNAL cnt1,cnt0:std_logic_vector(3 downto 0);
begin
process(clk)
begin
if(clr='1')then
cnt0<="0000";
cnt1<="0000";
elsif(clk'event and clk='1')then
if cnt1="0101" and cnt0="1001" then
co<='1';
cnt0<="0000";
cnt1<="0000";
elsif cnt0<"1001" then
cnt0<=(cnt0+1);
else
cnt0<="0000";
cnt1<=cnt1+1;
co<='0';
end if;
end if;
sec1<=cnt1;
sec0<=cnt0;
end process;
end sec;
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity minute is
port (clk:in std_logic;
min1,min0:out std_logic_vector(3 downto 0);
co:out std_logic);
end minute;
architecture min of minute is
SIGNAL cnt1,cnt0:std_logic_vector(3 downto 0);
begin
process(clk)
begin
if(clk'event and clk='1')then
if cnt1="0101" and cnt0="1001" then
co<='1';
cnt0<="0000";
cnt1<="0000";
elsif cnt0<"1001" then
cnt0<=(cnt0+1);
else
cnt0<="0000";
cnt1<=cnt1+1;
co<='0';
end if;
end if;
min1<=cnt1;
min0<=cnt0;
end process;
end min;
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity hour is
port(clk,en:in std_logic;
h1,h0:out std_logic_vector(3 downto 0));
end hour;
architecture beha of hour is
signal cnt1,cnt0:std_logic_vector(3 downto 0);
begin
process(clk)
begin
if(clk'event and clk='1') then
if cnt1="0010" and cnt0="0011" then
cnt1<="0000";
cnt0<="0000";
elsif cnt0<"1001" then
cnt0<=cnt0+1;
else
cnt0<="0000";
cnt1<=cnt1+1;
end if;
end if;
h1<=cnt1;
h0<=cnt0;
end process;
end beha;
上面分别是秒,分,时的代码。原理很简单,都是通过计数的方式,来一个时钟上升沿秒位就加一。当秒的低位到十了就进位给秒的高位,当秒的高位到六了就发出一个进位信号给分的地位。同理,分的高位以及时的低位和高位就设置好了。不同的是秒接分频后的时钟端,分接秒的进位信号,时接分的进位信号。
分频模块
library ieee;
use ieee.std_logic_1164.all;
entity fenpin is
port (clk:in std_logic;
clk1: out std_logic;
clk500: out std_logic;
clk1000: out std_logic;
clk16:out std_logic;
clk256: out std_logic);
end fenpin;
architecture fen_arc of fenpin is
begin
process(clk)
variable cnt1: integer range 0 to 24999999;
variable cnt500: integer range 0 to 49999;
variable cnt1000: integer range 0 to 24999;
variable cnt16: integer range 0 to 1669999;
variable cnt256: integer range 0 to 99999;
variable x: std_logic;
variable y: std_logic;
variable z: std_logic;
variable m: std_logic;
variable n: std_logic;
begin
if clk'event and clk = '1' then
if cnt1<24999999 then
cnt1:=cnt1+1;
else
cnt1:=0;
x:= not x;
end if;
end if;
clk1<=x;
if clk'event and clk = '1' then
if cnt500<49999 then
cnt500:=cnt500+1;
else
cnt500:=0;
y:= not y;
end if;
end if;
clk500<=y;
if clk'event and clk = '1' then
if cnt1000<24999 then
cnt1000:=cnt1000+1;
else
cnt1000:=0;
z:= not z;
end if;
end if;
clk1000<=z;
if clk'event and clk = '1' then
if cnt16<1669999 then
cnt16:=cnt16+1;
else
cnt16:=0;
m:= not m;
end if;
end if;
clk16<=m;
if clk'event and clk = '1' then
if cnt256<99999 then
cnt256:=cnt256+1;
else
cnt256:=0;
n:= not n;
end if;
end if;
clk256<=n;
end process;
end fen_arc;
数字时钟需要时钟信号的地方分别是秒的输入端,蜂鸣器的输入端,按键去抖电路,扫描显示电路。按照需要,分别分频出1Hz,500/1000Hz,256Hz,还有16Hz。(扫描好像是500Hz)。分频的方法也很简单,同样通过计数的方式可以达到分频的目的。
按键去抖模块
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity debounce is
port( clk,din: in std_logic;
dout: out std_logic);
end debounce;
architecture behav of debounce is
signal counter:integer range 0 to 50000000;
signal df_1,df_2,df,rst_n:std_logic;
constant timer:integer:=5000;
begin
process(clk)
begin
if clk'event and clk='1' then
df_1<=din;
df_2<=df_1;
end if;
df<=df_1 xor df_2;
rst_n<=df;
end process;
process(clk,rst_n)
begin
if rst_n='1' then
counter<=0;
elsif clk'event and clk='1' then
counter<=counter+1;
if counter=50000000 then
counter<=0;
end if;
if counter>=timer then
dout<=din;
end if;
end if;
end process;
end behav;
调时模块
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
entity ctrl is
port(clk:in std_logic; --10HZ
key1,key2,key3:in std_logic;
led1,led2,led3:out std_logic);
end ctrl;
architecture a of ctrl is
begin
process (clk)
begin
if(clk'event and clk='1')then
if(key1='0')then
led1<='1';
elsif(key1='1')then
led1<='0';
end if;
if(key2='0')then
led2<='1';
elsif(key2='1')then
led2<='0';
end if;
if(key3='0')then
led3<='1';
elsif(key3='1')then
led3<='0';
end if;
end if;
end process;
end a;
蜂鸣器报警模块
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity xiang is
port(m1,m0,s1,s0:in std_logic_vector(3 downto 0);
clk1,clk2:in std_logic;
speaker:out std_logic);
end xiang;
architecture sss_arc of xiang is
begin
process(clk1,clk2,m1,m0,s1,s0)
begin
speaker <= '0';
if(m1="0101"and m0="1001"and s1="0101"and s0="1001")then
speaker<=clk2;--1024HZ
else
speaker <= '1';
end if;
if(m1="0101"and m0="1001")then
if(s1="0101" )then
if(s0="0000" or s0="0010" or s0="0100" or s0="0110" or s0="1010")then
speaker<=clk1;--512HZ
end if;
end if;
else
speaker <= '1';
end if;
end process;
end sss_arc;
扫描信号输出模块
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity saomiao is
port(
clk500:in std_logic;--------------------------------时钟信号
cnt1:buffer integer);
end saomiao;
architecture one of saomiao is
begin
process(clk500)-------主要是让计算两个数码管的数值
begin
if clk500'event and clk500 = '1' then
if cnt1 = 5 then cnt1 <= 0;
else
cnt1 <= cnt1+1;
end if;
end if;
end process;
end one;
我这里主要是产生0-5的扫描信号,最后赋值给DigitalClock.vhd的扫描模块达到扫描的目的。扫描模块代码如下:
case cn1 is
when 0 => s <= h_1; q <="011111";------------cnt扫描信号,q位选信号,s数码管显示。
when 1 => s <= h_0; q <="101111";
when 2 => s <= min_1; q <="110111";
when 3 => s <= min_0; q <="111011";
when 4 => s <= sec_1; q <="111101";
when 5 => s <= sec_0; q <="111110";
when others => null;
end case;
二进制转八段数码管显示信号
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity f2e is
port(
clk:in std_logic;
high,low:in std_logic_vector(3 downto 0);--------------------------------时钟信号
num1,num0:out std_logic_vector(7 downto 0));
end f2e;
architecture beh of f2e is
begin
process(clk,high,low)
begin
case high is
when ("0000")=> num1 <= "11000000";
when ("0001")=> num1 <= "11111001";
when ("0010")=> num1 <= "10100100";
when ("0011")=> num1 <= "10110000";
when ("0100")=> num1 <= "10011001";
when ("0101")=> num1 <= "10010010";
when ("0110")=> num1 <= "10000010";
when ("0111")=> num1 <= "11111000";
when ("1000")=> num1 <= "10000000";
when ("1001")=> num1 <= "10010000";
when others=> num1 <= null;
end case;
case low is
when "0000"=> num0 <= "11000000";
when "0001"=> num0 <= "11111001";
when "0010"=> num0 <= "10100100";
when "0011"=> num0 <= "10110000";
when "0100"=> num0 <= "10011001";
when "0101"=> num0 <= "10010010";
when "0110"=> num0 <= "10000010";
when "0111"=> num0 <= "11111000";
when "1000"=> num0 <= "10000000";
when "1001"=> num0 <= "10010000";
when others=> num0 <= null;
end case;
end process;
end beh;
这个代码主要是把之前时钟输出的二进制数转为八段数码管相对应显示的字符。
结果展示
(woc,半夜两点的风吹的那个冷啊!)
小结
使用的芯片型号是Cyclone IV E EP4CE6F17C8,最后实现了数字时钟的显示,调时,以及特定时间报警。完成课设的要求。需要最后的工程文件或者sof文件可以私信获取。
Tips:引脚绑定方法——Pin Planner,对应引脚直接拖进去就行。