南京邮电大学
通达学院
课程设计报告
设计类别: EDA-VHDL
专业名称: 通信工程
班级学号: ~~~~~~~~ 学生姓名: ~~~~~ 基本题 : 数字时钟设计
综合题 : 数码管学号滚动显示
同小组成员:
学号:~~~~~~~~~
姓名:~~~~~~
指导教师: 王奇、梅中辉、周小燕、孔凡坤日期:2012年6月11日—6月22日
一、数字时钟
1.实验目的
(1)掌握VHDL语言的语法规范,掌握时序电路描述方法
(2)掌握多个数码管动态扫描显示的原理及设计方法
2.实验任务要求
要求学生设计一个时钟,并输出到数码管显示时,分,秒。
3.设计思路及VHDL代码
首先要设置一个时钟信号,根据时钟信号的变化来进行时钟的变化,从秒的变化到时的变化条件是不同的。将时分秒各分为为十位和各位即六位数字显示时间来分析。
原理图如下:
进
位
进
位
进
位
分针个位信号
清
零
清
零
清
零
清
零
清
零
VHDL源程序如下:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity shizhong is
port( clk:in std_logic;
led1:out std_logic_vector(6 downto 0);
led2:out std_logic_vector(6 downto 0);
led3:out std_logic_vector(6 downto 0);
led4:out std_logic_vector(6 downto 0);
led5:out std_logic_vector(6 downto 0);
led6:out std_logic_vector(6 downto 0));
end shizhong;
architecture main of shizhong is
signal hou1:std_logic_vector(3 downto 0);
signal hou2:std_logic_vector(3 downto 0);
signal min1:std_logic_vector(3 downto 0);
signal min2:std_logic_vector(3 downto 0);
signal sec1:std_logic_vector(3 downto 0);
signal sec2:std_logic_vector(3 downto 0);
begin
-------------------------------------------------------------
h110:process(clk,hou2,min1,min2,sec1,sec2)
begin
if clk'event and clk='1' then
if (hou1="0010" and hou2="0011")and(min1="0101" and min2="1001") and (sec1="0101" and
sec2="1001") then
hou1<="0000";
else if (hou2="1001"and(min1="0101" and min2="1001") and (sec1="0101" and sec2="1001"))
then
hou1<=hou1+1;
end if;
end if;
end if;
end process h110;
——————————时钟的十位
---------------------------------------------------------------
h220:process(clk,min1,min2,sec1,sec2,hou1)
begin
if clk'event and clk='1' then
if (hou1="0010" and hou2="0011")and(min1="0101" and min2="1001") and (sec1="0101" and
sec2="1001") then
hou2<="0000";
else if hou2="1001"and(min1="0101" and min2="1001") and (sec1="0101" and sec2="1001")
then
hou2<="0000";
else if((min1="0101" and min2="1001") and (sec1="0101" and sec2="1001")) then
hou2<=hou2+1;--speak<=clk;
end if;
end if;
end if;
end if;
end process h220;
——————————时钟的个位
--------------------------------------------------------------
m110:process(clk,min2,sec1,sec2)
begin
if clk'event and clk='1' then
if (min1="0101" and min2="1001") and (sec1="0101" and sec2="1001") then min1<="0000";
else if (min2="1001"and (sec1="0101" and sec2="1001"))then
min1<=min1+1;
end if;
end if;
end if;
end process m110;
——————————分钟的十位
--------------------------------------------------------------
m220:process(clk,sec1,sec2)
begin
if clk'event and clk='1' then
if min2="1001"and (sec1="0101" and sec2="1001")then
min2<="0000";
else if (sec1="0101" and sec2="1001") then
min2<=min2+1;
end if;
end if;
end if;
end process m220;
——————————分钟的个位
--------------------------------------------------------------
s110:process(clk)
begin
if clk'event and clk='1' then
if (sec1="0101" and sec2="1001")then
sec1<="0000";
else if sec2="1001"then
sec1<=sec1+1;
end if;
end if;
end if;
end process s110;
——————————秒钟的十位
-------------------------------------------------------------- s220:process(clk)
begin
if clk'event and clk='1' then
if sec2="1001" then
sec2<="0000";
else sec2<=sec2+1;
end if;
end if;
end process s220;
——————————秒钟的个位--------------------------------------------------------------- disp:process(hou1,hou2,min1,min2,sec1,sec2)
begin
case hou1 is
when "0000"=>LED1<="0111111";
when "0001"=>LED1<="0000110";
when "0010"=>LED1<="1011011";
when others=>LED1<="1000000";
end case;
case hou2 is
when "0000"=>LED2<="0111111";
when "0001"=>LED2<="0000110";
when "0010"=>LED2<="1011011";
when "0011"=>LED2<="1001111";
when "0100"=>LED2<="1100110";
when "0101"=>LED2<="1101101";
when "0110"=>LED2<="1111101";
when "0111"=>LED2<="0000111";
when "1000"=>LED2<="1111111";
when "1001"=>LED2<="1101111";
when others=>LED2<="1000000";
end case;
case min1 is
when "0000"=>LED3<="0111111"; when "0001"=>LED3<="0000110"; when "0010"=>LED3<="1011011"; when "0011"=>LED3<="1001111"; when "0100"=>LED3<="1100110"; when "0101"=>LED3<="1101101"; when others=>LED3<="1000000"; end case;
case min2 is
when "0000"=>LED4<="0111111"; when "0001"=>LED4<="0000110"; when "0010"=>LED4<="1011011"; when "0011"=>LED4<="1001111"; when "0100"=>LED4<="1100110"; when "0101"=>LED4<="1101101"; when "0110"=>LED4<="1111101"; when "0111"=>LED4<="0000111"; when "1000"=>LED4<="1111111"; when "1001"=>LED4<="1101111"; when others=>LED4<="1000000"; end case;
case sec1 is
when "0000"=>LED5<="0111111"; when "0001"=>LED5<="0000110"; when "0010"=>LED5<="1011011"; when "0011"=>LED5<="1001111"; when "0100"=>LED5<="1100110"; when "0101"=>LED5<="1101101"; when others=>LED5<="1000000"; end case;
case sec2 is
when "0000"=>LED6<="0111111"; when "0001"=>LED6<="0000110"; when "0010"=>LED6<="1011011"; when "0011"=>LED6<="1001111"; when "0100"=>LED6<="1100110"; when "0101"=>LED6<="1101101"; when "0110"=>LED6<="1111101"; when "0111"=>LED6<="0000111"; when "1000"=>LED6<="1111111"; when "1001"=>LED6<="1101111"; when others=>LED6<="1000000"; end case;
end process disp;
----------------------------------------------------------- end main;
4.仿真波形及分析
通过波形可以看出,秒,分,时各位之间可以很好地完成进位功能,秒钟达最大值59进一并清零,分钟达最大值59进一并清零,时钟打最大值23进一并清零,数字时钟功能可以实现。
5.实验总结与体会
本实验为基础题的第一题,整体功能与实际联系较为紧密,因此各模块的分析和设计方面难度减少了很多,通过这个课题的设计,我们初步认识了VHDL语言,以及quartus II 软件的具体应用方法,能够
很直观地将电路模块化分析并使用vhdl语言设计出来。
二、数码管学号滚动显示
1.实验目的
(1)掌握VHDL 语言的语法规范,掌握时序电路描述方法 (2)掌握多个数码管动态扫描显示的原理及设计方法
2.实验任务要求
要求学生在六个数码管滚动显示自己的学号(六位),每隔一定时间循环移位一次,学号为奇数则左移,学号为偶数则右移。间隔时间可由开关选择1秒,2秒,3秒和4秒。
3.设计思路及VHDL 代码
本题要求六位学号可以滚动显示,通过对其功能的理解,可以找出每个数字对应的数码管位置变化的规律。具体实现可以通过在每个脉冲上升沿触发学号中六个数字001908依次在六个数码管上输出,而在六个脉冲之后,六位学号还是依次输出,但是显示的数码管不同,首个数字在第二位数码管显示,以此类推,最后一位在第一位数码管显示。六个脉冲构成一个循环,以同上的方法类推显示即可实现学号的右移效果。显示的间隔时间可以通过源程序内改变运行次数来控制。
原理图如下:
模块设计:
输入&输出
输入: clk ------时钟信号
column ------行列式键盘的4列
输出: led_out ------数码管8段显示,可显示0~9,A~F led_sel ------选择6个数码管,‘1’表示点亮对应数码管
output ------分频后的时钟
Interval ------随学号移动而数值改变的寄存器
●分频电路模块
PROCESS(clk)--12分频电路
V ARIABLE counter: std_logic_vector(2 downto 0);--计数寄存器,12分频输入时钟为1Hz BEGIN
IF (clk'EVENT AND clk ='0') THEN --下降沿有效
counter := counter + 1 ;
IF (counter = 6) THEN
clk_temp <= NOT clk_temp; --分频后的时钟变化
counter := "000";
END IF;
END IF;
END PROCESS;
PROCESS(clk)--读取行列式键盘的键值
(这段程序是对时钟clock进行分频,进而得到新的时钟clk_temp,并赋值给输出output)
●移位控制模块
BEGIN
IF(clk'EVENT AND clk = '0')THEN
CASE column IS
WHEN "1110" =>
key_code <= "00";
WHEN "1101" =>
key_code <= "01";
WHEN "1011" =>
key_code <= "10";
WHEN "0111" =>
key_code <= "11";
WHEN OTHERS =>
key_code <= "00";
END CASE;
END IF;
END PROCESS;
process (clk_temp)
V ARIABLE time_count : std_logic_vector(1 DOWNTO 0);
begin
if (clk_temp 'event and clk_temp = '0') then--下降沿有效
time_count := time_count + 1;
CASE key_code IS
WHEN "00" =>
shift <= shift- 1; --数据右移1位
if(shift = "000") then
shift <="110";
end if;
WHEN "01" =>
if(time_count = "10") then
time_count := "00" ;
shift <= shift - 1; --数据右移1位
if(shift = "000") then
shift <="110";
end if;
end if;
WHEN "10" =>
if(time_count = "11") then
time_count := "00";
shift <= shift - 1; --数据右移1位
if(shift = "000") then
shift <="110";
end if;
end if;
WHEN "11" =>
if(time_count = "00") then
shift <= shift - 1; --数据右移1位
if(shift = "000") then
shift <="110";
end if;
end if;
WHEN OTHERS =>
shift <= shift - 1; --数据右移1位
if(shift = "000") then
shift <="110";
end if;
END CASE;
end if;
end process;
注: 该模块利用key_code的四个数值来控制四个case,由于time_count 初始值是00,在进入运算时是01,根据case的不同,运行次数不同,分别是一次,两次,三次和四次,根据这个来控制移动的间隔时间。
数码管显示模块
process (clk)------显示学号001908
V ARIABLE led_sel_llb :std_logic_vector(3 DOWNTO 0); --信号量,6个数码管显示的选择
begin
if (clk 'event and clk='0') then --时钟下降沿有效
if (led_sel_count = "0000") then --轮询6个数码管
led_sel_count <= "0101";
else
led_sel_count <= led_sel_count - "0001";
end if;
--0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff
-- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 空
case led_sel_count is --选择要要显示的值
when "0000" => led_out <= X"80"; --位置6,内容8
when "0001" => led_out <= X"c0"; --位置5,内容0
when "0010" => led_out <= X"90"; --位置4,内容9
when "0011" => led_out <= X"f9"; --位置3,内容1
when "0100" => led_out <= X"c0"; --位置2,内容0
when "0101" => led_out <= X"c0"; --位置1,内容0
when others => led_out <= X"92"; --其他情况下,位置6,内容5
end case;
led_sel_llb := led_sel_count + shift;
if (led_sel_llb >= "0110") then
led_sel_llb := led_sel_llb - "0110";
end if;
case led_sel_llb is --选择要被点亮的数码管
when "0000" => led_sel <= "000001"; --位置6
when "0001" => led_sel <= "000010"; --位置5
when "0010" => led_sel <= "000100"; --位置4
when "0011" => led_sel <= "001000"; --位置3
when "0100" => led_sel <= "010000"; --位置2
when "0101" => led_sel <= "100000"; --位置1
when others => led_sel <= "000001"; --其他情况下,位置6,内容5
end case;
end if;
end process;
注: 该模块中,led_sel用来表示选中的数码管,led_out 表示输出的数值。每一个clock 过来,都会输出一个数,依次是0-0-1-9-0-8,而数字输出在哪个数码管是由相同时刻的led_sel决定的。由于时钟频率很高,虽然每个时钟来临时只有一个数码管被点亮,但由于视觉停留,所以可以达到每个数码管都被点亮的效果。
VHDL源程序如下:
LIBRARY ieee ;
USE ieee.std_logic_1164.all ;
USE ieee.std_logic_unsigned.all ;
--显示模块
ENTITY llb IS
PORT (
clk : IN STD_LOGIC;
led_out : OUT STD_LOGIC_VECTOR(7 DOWNTO 0); --数码管8段显示,可显示0~9,A~F
led_sel : BUFFER STD_LOGIC_VECTOR(5 DOWNTO 0); --选择6个数码管,‘1’表示点亮对应数码管
output : OUT STD_LOGIC;
interval : OUT STD_LOGIC_VECTOR(2 downto 0);
column : IN STD_LOGIC_VECTOR(3 downto 0) --行列式键盘的4列) ;
END llb ;
ARCHITECTURE Behavior OF llb IS
signal clk_temp : std_logic := '1'; --用作分频后的电路时钟signal led_sel_count : std_logic_vector(3 DOWNTO 0); --信号量,6个数码管显示的选择
signal div_cnt : std_logic_vector(1 downto 0); --行扫描驱动
signal scan_key : std_logic_vector(3 DOWNTO 0); --扫描码寄存器
signal key_code : std_logic_vector(1 DOWNTO 0); --存储键值
signal shift : std_logic_vector(2 DOWNTO 0):= "110"; --控制数码管显示的数据右移
begin
output <= clk_temp;
interval <= shift;
PROCESS(clk)--12分频电路
V ARIABLE counter: std_logic_vector(2 downto 0);--计数寄存器,12分频输入时钟为1Hz
BEGIN
IF (clk'EVENT AND clk ='0') THEN --下降沿有效
counter := counter + 1 ;
IF (counter = 6) THEN
clk_temp <= NOT clk_temp; --分频后的时钟变化
counter := "000";
END IF;
END IF;
END PROCESS;
PROCESS(clk)--读取行列式键盘的键值
BEGIN
IF(clk'EVENT AND clk = '0')THEN
CASE column IS
WHEN "1110" =>
key_code <= "00";
WHEN "1101" =>
key_code <= "01";
WHEN "1011" =>
key_code <= "10";
WHEN "0111" =>
key_code <= "11";
WHEN OTHERS =>
key_code <= "00";
END CASE;
END IF;
END PROCESS;
process (clk_temp)
V ARIABLE time_count : std_logic_vector(1 DOWNTO 0);
begin
if (clk_temp 'event and clk_temp = '0') then--下降沿有效
time_count := time_count + 1;
CASE key_code IS
WHEN "00" =>
shift <= shift- 1; --数据右移1位
if(shift = "000") then
shift <="110";
end if;
WHEN "01" =>
if(time_count = "10") then
time_count := "00" ;
shift <= shift - 1; --数据右移1位
if(shift = "000") then
shift <="110";
end if;
end if;
WHEN "10" =>
if(time_count = "11") then
time_count := "00";
shift <= shift - 1; --数据右移1位
if(shift = "000") then
shift <="110";
end if;
end if;
WHEN "11" =>
if(time_count = "00") then
shift <= shift - 1; --数据右移1位
if(shift = "000") then
shift <="110";
end if;
end if;
WHEN OTHERS =>
shift <= shift - 1; --数据右移1位
if(shift = "000") then
shift <="110";
end if;
END CASE;
end if;
end process;
PROCESS(clk)--行扫描驱动,产生行扫描的值
BEGIN
IF(clk'EVENT AND clk = '0')THEN
div_cnt <= div_cnt + 1;
END IF;
END PROCESS;
PROCESS(div_cnt)--产生行扫描的值用于一行一行的轮询4行
BEGIN
CASE div_cnt IS
WHEN "00" =>
scan_key<="1110";
WHEN "01" =>
scan_key<="1101";
WHEN "10" =>
scan_key<="1011";
WHEN "11" =>
scan_key<="0111";
WHEN OTHERS =>
NULL;
END CASE;
END PROCESS;
process (clk)--显示学号001908
V ARIABLE led_sel_llb :std_logic_vector(3 DOWNTO 0); --信号量,6个数码管显示的
选择
begin
if (clk 'event and clk='0') then --时钟下降沿有效
if (led_sel_count = "0000") then --轮询6个数码管
led_sel_count <= "0101";
else
led_sel_count <= led_sel_count - "0001";
end if;
--0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff
-- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 空
case led_sel_count is --选择要要显示的值
when "0000" => led_out <= X"80"; --位置6,内容8
when "0001" => led_out <= X"c0"; --位置5,内容0
when "0010" => led_out <= X"90"; --位置4,内容9
when "0011" => led_out <= X"f9"; --位置3,内容1
when "0100" => led_out <= X"c0"; --位置2,内容0
when "0101" => led_out <= X"c0"; --位置1,内容0
when others => led_out <= X"92"; --其他情况下,位置6,内容5
end case;
led_sel_llb := led_sel_count + shift;
if (led_sel_llb >= "0110") then
led_sel_llb := led_sel_llb - "0110";
end if;
case led_sel_llb is --选择要被点亮的数码管
when "0000" => led_sel <= "000001"; --位置6
when "0001" => led_sel <= "000010"; --位置5
when "0010" => led_sel <= "000100"; --位置4
when "0011" => led_sel <= "001000"; --位置3
when "0100" => led_sel <= "010000"; --位置2
when "0101" => led_sel <= "100000"; --位置1
when others => led_sel <= "000001"; --其他情况下,位置6,内容5
end case;
end if;
end process;
end Behavior;
4.仿真波形及分析
学号右移功能:
11000000表示学号0 11111001表示学号1 10010000表示学号9 10000000表示学号8
100000表示左第一位数码管亮,010000表示第二位,以此类推。
初始状态,数码管显示学号0 0 1 9 0 8
右移一位,8 0 0 1 9 0
右移两位,0 8 0 0 1 9
右移三位,9 0 8 0 0 1
右移四位,1 9 0 8 0 0
右移五位,0 1 9 0 8 0
以上为一次循环。
循环间隔控制功能
显示间隔的控制由column决定,1110表示循环间隔为1秒,1101表示循环间隔为2秒,1011表示循环间隔为3秒,0111表示循环间隔为4秒。
间隔一秒情况:
间隔两秒情况:
间隔三秒情况:
间隔四秒情况:
5.实验总结与体会
本题为提高题第四题,整体功能和各模块的功能分析方面都比基础题要更为复杂,但由于与前一题同样是使用数码管扫描显示的设计方法,使的一些模块的设计方面可以很好地简化,虽然其中也有很多错误与缺陷,在学号的右移时也有一些问题,调试时问题更是不断,仿真波形也与课题要求有所差异,但最终还是达到了预期效果。通过实验,我们加深了对VHDL语言的认识和运用,对EDA的硬件应用方面也不仅仅是表面浅显的了解。不但学会了设计程序的方法,更重要的是学会了将一个课题进行功能分析,具体到各个功能子模块的分析方法。