资源描述
资料内容仅供您学习参考,如有不当之处,请联系改正或者删除。
南京邮电大学
课程设计报告
设计类别: EDA-VHDL
专业名称: 电子信息工程
班级学号: B08021717
学生姓名: 付祥旭
基本题 : 数字时钟设计
综合题 : 数码管学号动态显示
同小组成员:
学号:
姓名: 曾大千
指导教师: 王奇、 梅中辉、 周晓燕、 孔凡坤
日 期: 9月1日—9月21日
第一章 软件设计介绍
一、 各类设计环节的性质、 目的与任务
本课程设计是一门重要的专业基础实践课, 是《现代电子技术》或《EDA技术》等课程的后续实践课程, 未选前述课程的要求学生具备数字电路和C语言的基础。
本课程设计的目的和任务: 1.使学生全面了解如何应用该硬件描述语言进行高速集成电路设计; 2.经过软件设计环节与仿真环节使学生熟悉Quartus II设计与仿真环境; 3. 经过对基本题、 综合题的设计实践, 使学生掌握硬件系统设计方法( 自底向上或自顶向下) , 熟悉VHDL语言三种设计风格, 熟悉其芯片硬件实现的过程。
二、 实验内容
软件设计课题共分基本课题、 综合课题两档。基本课题2题, 12个学时完成; 综合课题共4题, 20个学时完成。
四、 考核办法
学生软件设计成绩考核来源于以下方面:
考勤及工作态度( 占10%)
软件设计报告( 占40%)
验收情况( 占50%)
五、 主要设备
微型计算
EDA-VHDL开发软件( QUARTUS2)
ALtera CPLD硬件实验开发系统
第二章 软件开发平台简介
1 Quartus II简介
Quartus II 提供了完整的多平台设计环境, 能满足各种特定设计的需要, 也是单芯片可编程系统( SOPC) 设计的综合性环境和SOPC开发的基本设计工具。Quartus II 设计工具完全支持VHDL、 Verilog的设计流程, 其内部嵌有VHDL、 Verilog逻辑综合器。Quartus II 具备仿真功能, 同时也支持第三方的仿真工具, 如Modelsim。
Quartus II 包括模块化的编译器。编译器包括的功能模块有分析/综合器( Analysis & Synthesis) 、 适配器(Fitter)、 装配器(Assembler)、 时序分析器(Timing Analyzer)、 设计辅助模块(Design Assistant)、 EDA网表文件生成器(EDA Netlist Writer)、 编辑数据接口(Compiler Database Interface)等。能够经过选择Sart Compilation 来运行所有的编译器模块, 亦能够经过选择Start 单独运行各个模块。还能够经过选择Compiler Tool(Tools 菜单), 在Compiler Tool 窗口中运行该模块来启动编译器模块。在Compiler Tool 窗口中, 能够打开该模块的设置文件或报告文件, 或打开其它相关窗口。
2 Quartus II设计基本流程
① 使用 New Project Wizard ( File 菜单) 建立新工程并指定目标器件或器件系列。
② 使用 Text Editor ( 文本编辑器) 建立 Verilog HDL、 VHDL 或 Altera硬件描述语言 (AHDL) 设计。 也能够使用 Block Editor ( 原理图编辑器) 建立流程图或原理图。流程图中能够包含代表其它设计文件的符号。 还能够使用 MegaWizard® Plug-In Manager 生成宏功能模块和IP内核的自定义变量, 在设计中将它们实例化。
③( 可选) 使用 Assignment Editor、 Settings 对话框( Assignments 菜单) 、 Floorplan Editor / LogicLock™ 功能指定初始设计的约束条件。
④( 可选) 使用 SOPC Builder 或 DSP Builder 建立系统级设计。
⑤ ( 可选) 使用 Software Builder 为 Excalibur™ 器件处理器或 Nios® 嵌入式处理器建立软件和编程文件。
⑥ 使用 Analysis & Synthesis 对设计进行综合。
⑦( 可选) 使用仿真器对设计执行功能仿真。
⑧ 使用 Fitter 对设计执行布局布线。 在对源代码进行少量更改之后, 还能够使用增量布局布线。
⑨ 使用 Timing Analyzer 对设计进行时序分析。
⑩ 使用仿真器对设计进行时序仿真。
第三章 软件设计内容
3.1数字时钟设计
1设计题目及其要求
要求学生设计一个时钟,并输出到数码管显示时, 分, 秒。
2设计原理
注: 本实验设计采用的是自已购买的开发板, 时钟为25MHZ, 3选8的数码管位选, 以及共阴型数码。
电路主要分为分频电路, 选择电路, 计数电路各译码扫描电路。
分频电路:
对开板上的晶振产生的25MHZ的调频进行12.5MHZ的分频产生1HZ的时钟信号.
选择电路:
对分频电路产生的1HZ的时钟信号,和秒计数器和分计数产生的进位信号进行选择,分别用于校分校时.
计数电路:
60计数器和24的计数器,分别对秒分和时进行计数.60计数器每计满60个数则产生一个进位信号,用于作为分钟计数器和小时计数器的时钟.
译码扫描电路:对于输出的秒分时数据时行译,以对应8段数码管的段选cout1~8,以及位选Key1~3.
下面是电路设计的原理图:
24计数器
译码与扫描电路
ckk
S21
选择
S11
分频电路
选择
60计数器
60计数器
Cout1~8
Key1-3
图1: 设计原理图
3、 分频电路
因为分频系数过大, 仿真不具有可操作性, 故把先把分频系数改小后进行仿真。
3.1逻辑仿真
对输入CLK1进行分频, 得到CLK2。这是把分频系数改小后的仿真图, 不代表实际电路。
3.2时序仿真
除有一定时间延迟外, 与逻辑仿真基本一致。
4选择电路
对分频电路产生的1HZ的时钟信号,和秒计数器和分计数产生的进位信号进行选择,分别用于校分校时.
4.1逻辑仿真
EN1=0 CLK=CLK1;
EN1=1 CLK=CLK2;
满足实验要求。
4.2时序仿真
有一定时间延迟外, 与逻辑仿真基本一致。
5、 六十进制计数器
5.1逻辑仿真
计数到3B( 16进制) =60( 10进制) 后产生一个进位脉冲, 满足实验要求。
5.2功能仿真
有一定时间延迟外, 与逻辑仿真基本一致。
6、 二十四进制计数器
6.1逻辑仿真
计数到17( 16进制) =23( 10进制) 重新从0计数, 满足实验要求。
6.2时序仿真
有一定时间延迟外, 与逻辑仿真基本一致。
7 译码扫描电路
因译码扫描电路的正误码仿真不具有可观察性, 故不在此仿真。
8 整体电路仿真
8.1逻辑仿真
从图能够看出S1控制校分电路, S2控制校时电路。当S1S2=00时, 按正常进行计时。
8.2时序仿真
有一定时间延迟外, 与逻辑仿真基本一致。
9总结: 本题超额完成题目要求, 增加了校时校分电路, 成为一个真正意义上的时钟。
3.2数码管学号动态显示
1设计题目及其要求
要求学生设计一个时钟,并输出到数码管显示时, 分, 秒。
2设计原理
注: 本实验设计采用的是自已购买的开发板, 时钟为25MHZ, 3选8的数码管位选, 以及共阴型数码。
电路主要分为分频电路, 选择电路, 计数电路各译码扫描电路。
分频电路:对开板上的晶振产生的25MHZ时钟进行分频产生1HZ、 2HZ、 3HZ、 4HZ的时钟信号.
选择电路:对分频电路产生的1HZ、 2HZ、 3HZ、 4HZ的时钟信号,由选择开关进行选择电路的时钟频率, 以控制学号移动的快慢。
循环电路路: 用于控制学号的循环左移( 08021717) ;
扫描译码电路: 译码扫描电路:对于输出的学号数据时行译,以对应8段数码管的段选cout1~8,以及位选Key1~3.
下面是对设计原理图
分频电路
选择电路
循环电路
译码扫描电路
clk
S1,s22
Cout1~8
Key1~3
3 分频电路: 因为分频系数过大, 仿真不具有可操作性, 故把先把分频系数改小后进行仿真。
3.1逻辑仿真
从图中能够看出输入一个高频时钟信号CLK1, 产生四个不同的低频信号CLK2, CLK3, CLK4, CLK5; 满足实验要求。
3.2时序仿真
从图中能够看出输入一个高频时钟信号CLK1, 产生四个不同的低频信号CLK2, CLK3, CLK4, CLK5; 满足实验要求。没有出现毛刺。
4选择电路
对分频电路产生的1HZ、 2HZ、 3HZ、 4HZ的时钟信号,由选择开关进行选择电路的时钟频率, 以控制学号移动的快慢。
4.1逻辑仿真
从图中能够看出
S1S0=‘00’CK=CLK1
S1S0=‘01’CK=CLK2
S1S0=‘10’CK=CLK3
S1S0=‘11’CK=CLK4
满足实验要求。
4.2时序仿真
从图中能够看出
S1S0=‘00’CK=CLK1
S1S0=‘01’CK=CLK2
S1S0=‘10’CK=CLK3
S1S0=‘11’CK=CLK4
没出现毛刺, 满足实验要求。
5 循环电路
用于控制学号的循环左移( 08021717)
5.1逻辑仿真
从图中能够看出每当CLK上升沿来临时, 学号移动一位, 而且循环移动。满足实验要求。
5.2时序仿真
除有一定延时外与逻辑仿真基本一致 。
6译码扫描电路
因译码扫描电路的正误码仿真不具有可观察性, 故不在此仿真。
7整体电路仿真
7.1逻辑仿真
从图中能够看出学号循环移位, 而且能够用S11, S10来控制循环的快慢。
逻辑仿真基本一致 。
7、 总结: 完全满足实验要求, 但在编码时因做了三个并列较大的分频, 导致资源占用过大。应该进行多次串联分频, 能够大大减少占用资源, 代码有待优化。
8调试过程与问题
编程和仿真基本上都没有什么问题, 可是在烧录到芯片内时却出现了一些问题, 在些仅举一个有意义的例子。
显示不稳定: 是因为在对数码管加上25MHZ的频率进行数码管进行扫描时, 因为过快, 因此导致不稳定, 一般加在扫描电路上的频率为几十到几百KHZ。
9 体会与建议
体会: 本次为期三周的软件设计, 共完成了一个基本题和一个综合题。可是因为我对基本题扩展了功能( 校时校分, 因此比综合题更显得复杂) 。
增强了自己VHDL的编程能力, 对VHDL的自顶向下的硬件设计思想有了更深入的了解。
因为自己以前学过VHDL, 对VHDL有一定的了解, 而且也做过一个相对比较大的项目, 也是采用VHDL编程, 因此本次的课题都不大难。
在完成课题期间, 我认为对课题的理解是重中之中, 只对对系统的功能有比较深入的了理解, 才能保证设计的合理性和正确性。然后就是自顶向下的思想, 如何将一个大型系统分为几个模块, 然后再把各模块组合起来, 如果能详细地分析出各个模块之间的逻辑关系, 一个复杂的项目也就显得很简单了。各个模块都是比较基本的, 只需要理解VHDL的语言法则, 就能够很轻松的完成。
我认为调试是系统设计过程中最难的, 也是最痛苦的。这需要设计者足够细心, 和有足够的耐心。因为不细心就会出现很大的错误, 而且很难找到。查错能力很重要, 这和一个人的编程有经验有关, 因此要想很快的找出错误, 减少这个过程的痛苦, 只能更多地训练。
建议: 本次软件设计的时间安排比较灵活, 均由同学自已把握, 但这样也使得时间比较零散, 很难集中精力。因此我建议应该集中安排软件设计时间。另外应该出一些更有挑战性的题供选择。
附录一、 数字时钟设计
library ieee; --顶层文件
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
entity d_clock is
port(s1,s2:in std_logic;--校时校分控制开关
ck:in std_logic;--输入25MHZ的时钟
css:out std_logic;--数码管和点阵现个区的选择, CSS=0选择数码管
key:out std_logic_vector(2 downto 0);--位选
data_out:out std_logic_vector(7 downto 0));--段选
end entity d_clock;
architecture behave of d_clock is
component df —分频模块
port(clk1:in std_logic;
clk2:buffer std_logic);
end component;
component c_24--24位计数器
port(clk:in std_logic;
cout:out std_logic_vector(4 downto 0)
);
end component
component c_60--60位计数器
port(clk:in std_logic;
cc:out std_logic;
cout:out std_logic_vector(5 downto 0));
end component;
component select2—选择频率, 即用来校时校分
port(clk1,clk2:in std_logic;
en1:in std_logic;
clk:out std_logic);
end component;
component show24—对0~23进行译码, 对应数码管8段
port(
tim_data:in std_logic_vector(4 downto 0);
cout1,cout2:out std_logic_vector(7 downto 0));
end component;
component show60—对0~59进行译码, 对应数码管8段
port(
tim_data:in std_logic_vector(5 downto 0);
cout1,cout2:out std_logic_vector(7 downto 0));
end component;
component SAOMIAO—动态扫描电路
port( clk:in std_logic;
cs:out std_logic;
da1,da2,da3,da4,da5,da6:in std_logic_vector(7 downto 0);
k:out std_logic_vector(2 downto 0);
da:out std_logic_vector(7 downto 0));
end component;
signal cp,cp1,cp2,ck1,ck2:std_logic;
signal c1,c2:std_logic_vector(5 downto 0);
signal c3:std_logic_vector(4 downto 0);
signal ten_h,d_h,ten_m,d_m,ten_s,d_s:std_logic_vector(7 downto 0);
begin
u1:df port map(clk1=>ck, clk2=>cp);
u2:c_60 port map(clk=>cp,cc=>ck1,cout=>c1);
u3:select2 port map(clk1=>ck1,clk2=>cp,en1=>s1,clk=>cp1);
u4:c_60 port map(clk=>cp1,cc=>ck2,cout=>c2);
u5:select2 port map(clk1=>ck2,clk2=>cp,en1=>s2, clk=>cp2);
u6:c_24 port map(clk=>cp2,cout=>c3);
u7: show60 port map(tim_data=>c1,cout1=>ten_s,cout2=>d_s);
u8:show60 port map(tim_data=>c2,cout1=>ten_m,cout2=>d_m);
u9:show24 port map(tim_data=>c3,cout1=>ten_h,cout2=>d_h);
u10:SAOMIAO port map(cs=>css,clk=>ck,da1=>ten_h,da2=>d_h,da3=>ten_m,da4=>d_m,da5=>ten_s,da6=>d_s,k=>key,da=>data_out);
end architecture behave;
library ieee;--分频电路
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity df is
port(clk1:in std_logic;--输入25MHZ
clk2:buffer std_logic);--输出1HZ
end entity df;
architecture behave of df is
signal g:std_logic_vector(4 downto 0);
begin
process(clk1)
begin
if clk1'event and clk1='1'then
if(g="0")then g<="0";
clk2<=not clk2;
else g<=g+"1";
end if;
end if;
end process;
end architecture behave;
library ieee;--24位计数器
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
entity c_24 is
port(clk:in std_logic;--输入时钟, 来1HZ校时, 或者来自分钟的进位
cout:out std_logic_vector(4 downto 0)—输出小时的数据
);
end entity c_24;
architecture behave of c_24 is
signal g:std_logic_vector(4 downto 0);
begin
process(clk)
begin
if(clk'event and clk='1')then
if g="10111"then
g<="00000";
else g<="00001"+g;
end if ;
end if;
cout<=g;
end process;
end architecture behave;
library ieee;--60计数器
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
entity c_60 is
port(clk:in std_logic; --输入时钟, 来自1HZ校分或者是秒计数时钟, 或者来自秋的进位
cc:out std_logic;--秒和分计数到60产生一个进位
cout:out std_logic_vector(5 downto 0));--输出秒或分钟的数据
end entity c_60;
architecture behave of c_60 is
signal g:std_logic_vector(5 downto 0);
begin
process(clk,g)
begin
if clk'event and clk='1' then
if g="111011" then
g<="000000";
cc<='1';
else g<=g+"000001";
cc<='0';
end if;
end if;
cout<=g;
end process;
end architecture behave;
library ieee;--选择是频率, 即选择是否校时校分
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity select2 is
port(clk1,clk2:in std_logic;--两个供选择的频率
en1:in std_logic;--控制开关
clk:out std_logic);--输出被选中的频率
end entity select2;
architecture behave of select2 is
begin
process(clk1,clk2,en1)
begin
if en1='0' then
clk<=clk1;
else clk<=clk2;
end if;
end process;
end architecture behave;
library ieee;-- 对0~23进行译码, 对应数码管8段
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
entity show24 is
port(
tim_data:in std_logic_vector(4 downto 0);--输入小时数据
cout1,cout2:out std_logic_vector(7 downto 0));--输出十位和个位对应的8段数码管对应的数据。
end entity show24;
architecture behave of show24 is
signal tcout1,tcout2:std_logic_vector(7 downto 0);
begin
process(tim_data)
begin
case tim_data is
when "00000"=>tcout1<="00000011";tcout2<="00000011";
when "00001"=>tcout1<="00000011";tcout2<="10011111";
when "00010"=>tcout1<="00000011";tcout2<="00100101";
when "00011"=>tcout1<="00000011";tcout2<="00001101";
when "00100"=>tcout1<="00000011";tcout2<="10011001";
when "00101"=>tcout1<="00000011";tcout2<="01001001";
when "00110"=>tcout1<="00000011";tcout2<="01000001";
when "00111"=>tcout1<="00000011";tcout2<="00011111";
when "01000"=>tcout1<="00000011";tcout2<="00000001";
when "01001"=>tcout1<="00000011";tcout2<="00011001";
when "01010"=>tcout1<="10011111";tcout2<="00000011";
when "01011"=>tcout1<="10011111";tcout2<="10011111";
when "01100"=>tcout1<="10011111";tcout2<="00100101";
when "01101"=>tcout1<="10011111";tcout2<="00001101";
when "01110"=>tcout1<="10011111";tcout2<="10011001";
when "01111"=>tcout1<="10011111";tcout2<="01001001";
when "10000"=>tcout1<="10011111";tcout2<="01000001";
when "10001"=>tcout1<="10011111";tcout2<="00011111";
when "10010"=>tcout1<="10011111";tcout2<="00000001";
when "10011"=>tcout1<="10011111";tcout2<="00011001";
when "10100"=>tcout1<="00100101";tcout2<="00000011";
when "10101"=>tcout1<="00100101";tcout2<="10011111";
when "10110"=>tcout1<="00100101";tcout2<="00100101";
when "10111"=>tcout1<="00100101";tcout2<="00001101";
when others=>tcout1<="11111111";tcout2<="11111111";
end case;
end process;
cout1<=not tcout1;
cout2<=not tcout2;
end architecture behave;
library ieee; 对0~59进行译码, 对应数码管8段
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
entity show60 is
port(
tim_data:in std_logic_vector(5 downto 0);--输入秒或分钟的数据
cout1,cout2:out std_logic_vector(7 downto 0)); --输出十位和个位对应的8段数码管
end entity show60;
architecture behave of show60 is
signal tcout1,tcout2:std_logic_vector(7 downto 0);
begin
process(tim_data)
begin
case tim_data is
when "000000"=>tcout1<="00000011";tcout2<="00000011";
when "000001"=>tcout1<="00000011";tcout2<="10011111";
when "000010"=>tcout1<="00000011";tcout2<="00100101";
when "000011"=>tcout1<="00000011";tcout2<="00001101";
when "000100"=>tcout1<="00000011";tcout2<="10011001";
when "000101"=>tcout1<="00000011";tcout2<="01001001";
when "000110"=>tcout1<="00000011";tcout2<="01000001";
when "000111"=>tcout1<="00000011";tcout2<="00011111";
when "001000"=>tcout1<="00000011";tcout2<="00000001";
when "001001"=>tcout1<="00000011";tcout2<="00011001";
when "001010"=>tcout1<="10011111";tcout2<="00000011";
when "001011"=>tcout1<="10011111";tcout2<="10011111";
when "001100"=>tcout1<="10011111";tcout2<="00100101";
when "001101"=>tcout1<="10011111";tcout2<="00001101";
when "001110"=>tcout1<="10011111";tcout2<="10011001";
when "001111"=>tcout1<="10011111";tcout2<="01001001";
when "010000"=>tcout1<="10011111";tcout2<="01000001";
when "010001"=>tcout1<="10011111";tcout2<="00011111";
when "010010"=>tcout1<="10011111";tcout2<="00000001";
when "010011"=>tcout1<="10011111";tcout2<="00011001";
when "010100"=>tcout1<="00100101";tcout2<="00000011";
when "010101"=>tcout1<="00100101";tcout2<="10011111";
when "010110"=>tcout1<="00100101";tcout2<="00100101";
when "010111"=>tcout1<="00100101";tcout2<="00001101";
when "011000"=>tcout1<="00100101";tcout2<="10011001";
when "011001"=>tcout1<="00100101";tcout2<="01001001";
when "011010"=>tcout1<="00100101";tcout2<="01000001";
when "011011"=>tcout1<="00100101";tcout2<="00011111";
when "011100"=>tcout1<="00100101";tcout2<="00000001";
when "011101"=>tcout1<="00100101";tcout2<="00001101";
when "011110"=>tcout1<="00001101";tcout2<="00000011";
when "011111"=>tcout1<="00001101";tcout2<="10011111";
when "100000"=>tcout1<="00001101";tcout2<="00100101";
when "100001"=>tcout1<="00001101";tcout2<="00001101";
when "100010"=>tcout1<="00001101";tcout2<="10011001";
when "100011"=>tcout1<="00001101";tcout2<="01001001";
when "100100"=>tcout1<="00001101";tcout2<="01000001";
when "100101"=>tcout1<="00001101";tcout2<="00011111";
when "100110"=>tcout1<="00001101";tcout2<="00000001";
when "100111"=>tcout1<="00001101";tcout2<="00001101";
when "101000"=>tcout1<="10011001";tcout2<="00000011";
when "101001"=>tcout1<="10011001";tcout2<="10011111";
when "101010"=>tcout1<="10011001";tcout2<=
展开阅读全文