数字逻辑实验报告(马钊+袁泉+杨晨笛+罗亚群)

北京邮电大学课程设计报告

数字逻辑实验报告马钊袁泉杨晨笛罗亚群

注:评语要体现每个学生的工作情况,可以加页。

数字逻辑与数字系统课程设计

目录

实验一:简易电子琴 ............................................................................................................................... 3

实验二:简易频率计 ............................................................................................................................... 6

实验三:交通灯控制器设计 ................................................................................................................. 11

实验四:电子钟设计 ............................................................................................................................. 17

实验五:药片装瓶系统设计 ................................................................................................................. 26

附:数字逻辑与数字系统课程设计心得体会 ..................................................................................... 34

2

数字逻辑与数字系统课程设计

实验一:简易电子琴

一、实验目的

①掌握较复杂逻辑的设计和调试。

②掌握用VHDL语言设计数字逻辑电路。

③掌握ispLEVER软件的使用方法。

④掌握ISP器件的使用。

⑤用途: 有电子琴的基本功能,可弹奏出简单的乐曲。

二、实验所用器件和设备

在系统可编程逻辑器件ISP1032 一片

示波器 一台

万用表或逻辑笔 一只

TEC-5实验系统,或TDS-2B数字电路实验系统 一台

三、实验原理

用VHDL设计一个简易电子琴。

有8个按键,每键代表一个音符, 1、2、3、4、5、6、7、i各音符按一定的顺序排列,须符合电子琴的按键排列顺序。

每个音符对应特定的频率的方波信号。

方波信号由多模计数器产生。

方波信号占空比可改变音量大小。

数字逻辑实验报告马钊袁泉杨晨笛罗亚群

图1-1 简易电子琴原理图

四、设计方案

输入的主频=50KHz,不同的键产生不同频率的输出,输出由多模计数器产生。

多模计数器:M(模)=50000/f

数字逻辑实验报告马钊袁泉杨晨笛罗亚群

3

数字逻辑与数字系统课程设计

多模计数器输出波形:

数字逻辑实验报告马钊袁泉杨晨笛罗亚群

二分频计数器:

数字逻辑实验报告马钊袁泉杨晨笛罗亚群

(改变音量使输出信号占空比为50%)

五、代码实现

LIBRARY ieee;

USE ieee.std_logic_1164.all;

USE ieee.std_logic_unsigned.all;

ENTITY piano is

port(clk:in std_logic;--时钟源为50kHz

k:in std_logic_vector(7 downto 0);--从高位到低位对应1,2,3,4,5,6,7,i dout:out std_logic);--输出至喇叭

end piano;

ARCHITECTURE art of piano is

signal temp,m:integer range 0 to 127;--temp为计数值,m为计数器模值 begin

process(clk,k)--模m计数器

variable a:std_logic;

begin

case k is

when "10000000" => m<=95;

when "01000000" => m<=84;

when "00100000" => m<=75;

when "00010000" => m<=71;

when "00001000" => m<=63;

when "00000100" => m<=56;

when "00000010" => m<=50;

when "00000001" => m<=47;

when others => m<=0;

end case;

4

数字逻辑与数字系统课程设计

if(clk'event and clk='1') then --对50kHz原始信号进行m分频,再进行2分频

if (temp=m) then

temp<=0;

a:=not a; --“翻转”信号,实现信号占空比50%

else

temp<=temp+1;

end if;

end if;

dout<=a;

end process;

end ARCHITECTURE;

六、实验中出现的问题及解决方法

由于学习VHDL编程已经过去一个学期,很多东西都已经不太清楚了。第一个实验比较基础也比较简单,所以过程中并没有遇到什么大问题,主要是一些小细节上的问题。

比方说,首先是VHDL的语法已经不太熟练了,因此在复习VHDL硬件编程的基础上着重对语法进行了复习和记忆。例如case-is-when语句和if-then-elsif语句等。

然后,此实验中主要涉及的两个知识:模m计数器和二分频计数器。m的值是由k来决定的,也就是由开关来控制。而对信号二分频的时候,需要设定一个变量,在计数值加到m的时候对信号进行翻转,从而达到分频目的。

另外,是在对ISP器件的使用上。以前只有一次实验实践操作过ISP器件,那时是在老师一步一步指导下进行操作,了解得并不是很全面很深入。这次完全是自己来操作了,所以对每一个步骤都会很留意。对该软件的使用上也出现过一些错误,多次重来后解决。

七、本次实验的收获

作为小学期数字逻辑课程设计的第一个实验,充分体现了其基础性和概括性。为了对程序有更好地把握,不仅复习了一学期前所学习的VHDL的知识,更在此基础上扩宽了对VHDL的理解和认识,学到了更多的知识。最重要的,是体会到了学以致用的乐趣。

另外,对在系统编程了设计流程也有了一定的掌握,对ISP器件的使用也有一定的熟悉。作为一个开始的基础实验,学到的东西还是挺多的。

5

数字逻辑与数字系统课程设计

实验二:简易频率计

一、实验目的

⑴掌握较复杂逻辑的设计和调试。

⑵掌握用VHDL语言设计数字逻辑电路。

⑶掌握ispLEVER软件的使用方法。

⑷掌握ISP器件的使用。

⑸了解频率计的初步知识。

二、实验所用器件和设备

在系统可编程逻辑器件ISP1032 一片

示波器 一台

万用表或逻辑笔 一只

TEC-5实验系统,或TDS-2B数字电路实验系统 一台

三、实验内容

设计一个简易频率计,用于测量1MHz以下数字脉冲信号的频率。闸门只有1s一档。测量结果在数码管上显示出来。不测信号脉宽。用一片ISP芯片实现此设计,并在实验台上完成调试,建议设计采用VHDL语言编写。

四、设计思路

⑴频率计的基本工作原理如下:首先产生一系列准确闸门信号,例如1ms,0.1s和1s等。然后用这些闸门信号控制一个计数器对被测脉冲信号进行计数,最后将结果显示出来。如果闸门信号是1s,那么1s内计数的结果就是被测信号的频率。如果闸门信号是1ms,那么计数结果是被测信号频率的千分之一,或者说结果是以kHz为单位的频率值。

⑵频率计中,最原始的时基信号准确度一定要高。建议用实验台上的5kHz时钟信号做原始时基信号。

⑶1s的闸门信号,由5kHz时钟经5K分频后,再经2分频产生。这样产生的闸门信号脉宽是1s,占空比是50%。在2s的时间内,1s用于计数,1s用于显示结果。

⑷用于被测信号计数的计数器应采用十进制。测得的结果可直接送实验台上的6个数码管显示。每次对被测信号计数前,计数器应被清零。

数字逻辑实验报告马钊袁泉杨晨笛罗亚群

数字逻辑实验报告马钊袁泉杨晨笛罗亚群

图2-1 简易频率计原理图 图2-2 简易频率计模块设计

6

数字逻辑与数字系统课程设计

五、设计方案

数字逻辑实验报告马钊袁泉杨晨笛罗亚群

LIBRARY ieee;

USE ieee.std_logic_1164.all;

USE ieee.std_logic_unsigned.all;

ENTITY frequency is

port(clk1,clk2:in std_logic; --clk1为5kHz的原始时基信号,clk2为被测信号

dout:out std_logic_vector(19 downto 0); --输出至低5位数码管

dec:out std_logic_vector(6 downto 0)); --译码结果送最高位数码管

end frequency;

ARCHITECTURE art of frequency is

component counter10 --十进制计数器元件声明

port (clk,cd,en:in std_logic; --clk时钟,cd清零,en使能

qout:out std_logic_vector(3 downto 0); --计数输出

cout:out std_logic); --进位输出

end component;

signal temp:std_logic_vector(19 downto 0); --十进制计数结果的低5位

signal dec_temp:std_logic_vector(3 downto 0); --十进制计数结果的最高位

signal c:std_logic_vector(5 downto 0); --计数器每一位的进位信号

signal gate_sig,clr:std_logic; --闸门信号,清零信号

signal count:integer range 0 to 4999; --用于产生闸门信号时计数

begin

u1:counter10 PORT MAP (clk2,clr,gate_sig,temp(3 downto 0),c(0)); --6个十进制计数器 u2:counter10 PORT MAP (c(0),clr,gate_sig,temp(7 downto 4),c(1)); --低位计数器进位信号作 u3:counter10 PORT MAP (c(1),clr,gate_sig,temp(11 downto 8),c(2)); --为高位计数器时钟信号 u4:counter10 PORT MAP (c(2),clr,gate_sig,temp(15 downto 12),c(3));

u5:counter10 PORT MAP (c(3),clr,gate_sig,temp(19 downto 16),c(4));

u6:counter10 PORT MAP (c(4),clr,gate_sig,dec_temp(3 downto 0),c(5));

PROCESS1:process(clk1) --对5kHz原始信号进行5000分频,再进行2分频,产生闸门信号 begin

if (clk1'event and clk1='1') then

if (count=4999) then

count<=0;

gate_sig<=not gate_sig; --“翻转”闸门信号,实现闸门信号占空比50% else

count<=count+1;

end if;

end if;

end process PROCESS1;

clr<='0' when (count=4999 and gate_sig='0') else --在计数前对计数器清零

7

数字逻辑与数字系统课程设计

'1';

dout<=temp;

PROCESS2:process(dec_temp) --计数器最高位七段译码

begin

case dec_temp is

when "0000" => dec<="1111110";

when "0001" => dec<="0110000";

when "0010" => dec<="1101101";

when "0011" => dec<="1111001";

when "0100" => dec<="0110011";

when "0101" => dec<="1011011";

when "0110" => dec<="0011111";

when "0111" => dec<="1110000";

when "1000" => dec<="1111111";

when "1001" => dec<="1110011";

when others => dec<="0000000";

end case;

end process PROCESS2;

end art;

数字逻辑实验报告马钊袁泉杨晨笛罗亚群

LIBRARY ieee;

USE ieee.std_logic_1164.all;

USE ieee.std_logic_unsigned.all;

ENTITY counter10 is

port(clk,cd,en:in std_logic; --clk时钟,cd清零,en使能

qout:out std_logic_vector(3 downto 0); --计数输出

cout:out std_logic); --进位输出

end counter10;

ARCHITECTURE art of counter10 is

signal temp:std_logic_vector(3 downto 0);

begin

process(clk,en,cd)

begin

if (cd='0') then --cd有效计数器清零

temp<="0000";

elsif (clk'event and clk='0') then --时钟下降沿触发

if (temp="1001" and en='1') then --使能有效时计数,无效时停止计数 temp<="0000";

elsif (en='1') then

8

数字逻辑与数字系统课程设计

temp<=temp+1;

end if;

end if;

end process;

qout<=temp;

cout<='1' when temp="1001" else --计数到9时产生进位信号

'0';

end art;

六、调试中出现的问题及解决方法

有了前面简易电子琴的设计,巩固了ISP器件的设计流程、编程方式,VHDL的基本结构、语法要点、设计技巧等,编程过程中比较顺利,但是也遇到了一些问题。

① 计数器采用异步级联方式,即最低位计数器接入待测信号作为时钟,其余计数器接入低位计

数器的进位信号作为时钟,其中计数器在计到9时产生进位信号,利用时钟上升沿触发。但是,由此产生的问题是高位提前加1(即:000006,000007,000008,000019,000010,000011,000012)。这个问题很容易解决,把时钟改为下降沿触发即可。

② 如何用闸门信号控制计数器是否计时?在十进制计数器模块中添加使能信号en(en=‘1’计

数器进行加1计数,en=‘0’时计数器保持),将闸门信号作为使能信号接入,即可实现1s计数,1s显示。

③ 利用闸门信号gate_sig=‘1’对待测信号进行计数,gate_sig=‘0’显示待测信号频率数,遇

到的问题是频率个数会累加。解决的方法是:在十进制计数器模块中增加清零信号。在闸门信号为‘0’的最后一个计数周期(即count=4999 and gate_sig='0')时将频率计清零。

④ elsif (clk'event and clk='0' and en='1') then语句编译不通过,if语句中只能单独判断时钟的上升

沿(或者下降沿),不能在添加其他的判断条件。解决方法是在elsif (clk'event and clk='0') then下面的每个if-else语句中加en=‘1’的判断条件。即,

if (temp="1001" and en='1') then

elsif (en='1') then

end if;

⑤ 由于最初未在实验室编程,对实验台不熟悉,对6个十进制计数器的输出都进行了七段显示

译码,后来看到课本上的实验提示“测得的结果可直接送实验台上的6个数码管显示”后,又把七段显示译码部分删去了。后来到了实验室才发现最高位需要七段显示译码,其余位直接将8421码接入即可。

⑥ 由于是第一次在实践中运用元件例化语句(component),不是很熟悉(不知道2个.vhd文件

怎样关联起来),通过对上学期课程的复习,以及逐步的摸索,对例化语句有了深入的了解。

七、层次设计的体会

这次实验采用层次设计利用闸门信号模块与(一位)十进制计数器模块对待测信号的上升沿进行计数。有两个底层模块:一个模块产生0.5Hz占空比为50%的闸门信号;另一个模块是0~9计数的十进制计数器。

利用层次设计的方法,结构明了、思路清晰、便于分析。并且将复杂问题简单化、模块化、结构化,抽象问题具体化、简单化。特别是元件例化语句使结构功能、端口连接一目了然,可以代码复用,避免重复代码,还可以增强代码的可读性。

八、比较不同种描述方式的心得

实验中结构体的三种描述方式都用到了:数据流描述、结构描述、行为描述。数据流描述(用布

9

数字逻辑与数字系统课程设计

尔代数描述系统的输入和输出)逻辑清晰、描述简单。结构描述(分层次描述,高层可调用低层模块)使程序模块划分清晰,便于从宏观上把握程序功能,便于整体设计。行为描述更容易把握程序对于不同输入或者信号所做的动作。根据不同情况选择不同描述方法可以使程序得到优化。

九、本次设计的收获和不足

本次设计最大的收获就是在电子琴的基础上对“分频”以及“计数器”有了熟练掌握,进一步熟悉了ispLEVER软件和ISP器件的使用与下载方法,这样会对后面两个实验帮助很大。首次尝试了例化语句的应用,对VHDL的理解与应用有上了一个一个不小的台阶。对硬件编程语言和C++等高级语言的区别与联系有了较深刻的理解,学会了用“硬件的方式”(比如说并行语句)思考问题。另外,小组成员之间的配合也更加默契,效率也在不断地提高。

由于实验台只提供了500kHz、50kHz、5kHz三种频率的信号,只进行了3组测试,结果完全正确,而没有再编写程序产生其他频率信号进行测试。

十、实验分工

实验调试由全体成员完成,其中顶层模块主要由马钊和罗亚群负责,计数器模块主要由袁泉和杨晨笛负责。

10

数字逻辑与数字系统课程设计

实验三:交通灯控制器设计

一、实验目的

①学习采用状态机方法设计时序逻辑电路。

②掌握ispLEVER软件的使用方法。

③掌握用VHDL语言设计数字逻辑电路。

④掌握ISP器件的使用。

二、实验所用器件和设备

在系统可编程逻辑器件ISP1032 一片

示波器 一台

万用表或逻辑笔 一只

TEC-5实验系统,或TDS-2B数字电路实验系统 一台

三、实验内容

以实验台上的4个红色电平指示灯,4个绿色电平指示灯模仿路口的东南西北4个方向的红,绿,黄交通灯。控制这些交通灯,使它们按下列规律亮,灭。

(1) 初始状态为4个方向的红灯全亮,时间1s。

(2) 东,西方向绿灯亮,南,北方向红灯亮。东,西方向通车,时间5s。

(3) 东,西方向黄灯闪烁,南,北方向红灯,时间2s。

(4) 东,西方向红灯亮,南,北方向绿灯亮。南,北方向通车,时间5s。

(5) 东,西方向红灯闪烁,南,北方向黄灯闪烁,时间2s。

(6) 返回(2),继续运行。

(7) 如果发生紧急事件,例如救护车,警车通过,则按下单脉冲按钮,使得东,南,西,北四个

方向红灯亮。紧急事件结束后,松开单脉冲按钮,将恢复到被打断的状态继续运行。

四、设计思路

(1) 熟悉掌握使用枚举类型数据格式结合CASE语句实现状态机设

计。

(2) 这是一个典型的时序状态机,一共6个大的状态。由于各个状态

停留时间不同,但都是秒的倍数。可以考虑设计当前状态与下一状态两

个枚举型数据,每秒刷新旧状态值,各个状态的timeout时对下一状态赋

值。

(3) 黄灯闪烁可通过连续两0.2s,灭0.2s实现。

(4) 选择实验台上的5kHz频率时钟,作为设计中分频的初始时钟。

(5) 紧急事件发生时,要注意保存必要的信息,已被紧急事件结束

后,恢复到原状态继续运行使用。

图3-1 交通灯控制框图

五、设计方案

LIBRARY ieee;

USE ieee.std_logic_1164.all;

ENTITY tralight is

port

数字逻辑实验报告马钊袁泉杨晨笛罗亚群

(

11

数字逻辑与数字系统课程设计

restart,emergency,clk: in std_logic;

--restart为复位信号,emergency为紧急事件信号,clk为实验台上的5kHz频率时钟, 作为设计中分频的初始时钟

light : out std_logic_vector(11 downto 0));

--light输出到实验台上12个指示灯

ARCHITECTURE art of tralight is

type trafficstate is (s0,s1,s2,s3,s4); --交通灯状态

signal current_state,next_state: trafficstate; --当前状态,转移状态

signal en1,en2,en3,en4, c,c1,c2,c3,c4: std_logic;

--en为计数器使能控制信号,c为计数器进位信号

signal temp1: integer range 0 to 49999; --产生1s计数器时计数

signal temp2: integer range 0 to 99999; --产生2s计数器时计数

signal temp3: integer range 0 to 249999; --产生5s计数器时计数

signal temp4: integer range 0 to 9999; --产生0.2s计数器时计数

begin

-----1s计数器,对5kHz原始信号进行5000分频,每秒产生一个进位脉冲c1

process(clk,en1)

begin

if (clk'event and clk='1') then

if (temp1=49999 and en1='1' and emergency='0') then

temp1<=0;

c1<='1';

elsif (en1='1' and emergency='0') then

temp1<=temp1+1;

c1<='0';

end if;

end if;

if (en1='0') then

c1<='0';

temp1<=0;

end if;

end process;

-----2s计数器,对5kHz原始信号进行10000分频,每两秒产生一个进位脉冲c2

process(clk,en2)

begin

if (clk'event and clk='1') then

if (temp2=99999 and en2='1' and emergency='0') then

temp2<=0;

c2<='1';

elsif (en2='1'and emergency='0') then

temp2<=temp2+1;

c2<='0';

12

数字逻辑与数字系统课程设计

end if;

end if;

if (en2='0') then

c2<='0';

temp2<=0;

end if;

end process;

-----5s计数器,对5kHz原始信号进行25000分频,每五秒产生一个进位脉冲c3 process(clk,en3)

begin

if (clk'event and clk='1') then

if (temp3=249999 and en3='1' and emergency='0') then

temp3<=0;

c3<='1';

elsif (en3='1' and emergency='0') then

temp3<=temp3+1;

c3<='0';

end if;

end if;

if (en3='0') then

temp3<=0;

c3<='0';

end if;

end process;

--0.2s计数器,对5kHz原始信号进行10000分频,每0.2秒产生一个进位脉冲c4 process(clk,en4)

begin

if (clk'event and clk='1') then

if (temp4=9999 and en4='1') then

temp4<=0;

c4<=not c4;

elsif (en4='1') then

temp4<=temp4+1;

end if;

end if;

end process;

c<=c1 or c2 or c3; --进位信号控制状态转移

process (c,restart) --状态转移进程

begin

if (restart='1') then--复位信号使状态回到s0,即红灯全亮1s

current_state<=s0;

13

数字逻辑与数字系统课程设计

elsif (c'event and c='0') then--遇到计数器进位转移到下一状态

current_state<=next_state;

end if;

end process;

process (current_state,emergency) --控制状态转移,信号灯亮灭

begin

if(emergency='1') then--紧急状态红灯全亮

light<="000000001111";

else

case current_state is

when s0=> --初始四个方向的红灯全亮,延时1秒 light<="000000001111";

en2<='0';

en3<='0';

en1<='1';

next_state<=s1;

when s1=> --东西方向绿灯亮,南北方向红灯亮,延时5秒 en1<='0';

en2<='0';

light<="010100001010";

en3<='1';

next_state<=s2;

when s2=> --东西方向黄灯闪,南北方向红灯亮,延时2秒 en3<='0';

en2<='1';

en4<='1';

light(11 downto 7 )<="00000";

light(6)<=c4;

light(5)<='0';

light(4)<=c4;

light(3 downto 0)<="1010";

next_state<=s3;

when s3=> --东西方向红灯亮,南北方向绿灯亮,延时5秒 en2<='0';

en4<='0';

en3<='1';

light<="101000000101";

next_state<=s4;

when s4=> --东西方向红灯闪,南北方向黄灯闪,延时2秒 en3<='0';

en2<='1';

en4<='1';

light(11 downto 8 )<="0000";

14

数字逻辑与数字系统课程设计

light(7)<=c4;

light(6)<='0';

light(5)<=c4;

light(4 downto 0)<="00101";

next_state<=s1;

end case;

end if;

end process;

end art;

六、调试中出现的问题及解决方法

这次实验总体思路比较清晰,不需要太多的输入,只有复位和紧急状态输入,但是在具体实现上遇到了一些问题,有的地方有毛刺现象。

① 对于实验中要求的四个时间计数器,开始我们考虑的是只写一个0.2s的计数器,放在例化元件里,状态需要的时间可以多次调用该元件,但是实际操作中需要用控制信号控制计数器的运行,在一个计数器里不好控制,最终我们采用四个计数器的进程。

② 在交通灯系统运行过程中,我们发现同一个状态的时间是不稳定的,如5s状态可能只进行了2s就跳到下一个状态。这其实是一个很严重的问题,也是我们最后才想明白的。解决方法是:控制信号使计数器停止工作时(既状态转移使en=0),将进位信号c和计数的temp都清零。

③ 一开始我们将紧急情况单独设置为一个状态,再次状态下所有计数器控制信号使计数器停止工作,但是由于问题2,计数的temp清零,无法保存现场。对于此问题,我们采用另一种方法,不转移状态,只是单独让计数器停止工作,既让计数器在 emergency=1的情况下,每当来一个脉冲,计数器加1。

④ 对于黄灯闪的情况,我们发现light(11 downto 0 )<="0000&c4&0&c4&00101"并不能使黄灯闪烁,改为light(11 downto 8)<= "0000";light(7)<=c4;light(6)<= '0';light(5)<=c4;

light(4 downto 0)<= "00101";问题即可解决。

七、层次设计的体会

实验思路比较简单,我们没有采用元件例化的方法,但是模块划分仍然很清晰。程序可分为计数器模块,状态转移模块,输出模块(控制灯亮灭)。层次设计将大问题分解为较小的问题,可以提高效率,使思路清晰。

八、比较不同种描述方式的心得

实验中结构体的三种描述方式都用到了:数据流描述、结构描述、行为描述。数据流描述逻辑清晰、描述简单。结构描述使程序模块划分清晰,便于从宏观上把握程序功能,便于整体设计。行为描述更容易把握程序对于不同输入或者信号所做的动作。根据不同情况选择不同描述方法可以使程序得到优化。

九、本次设计的收获和不足

本次设计我们首次用到了枚举类型数据格式结合CASE语句实现状态机设计,了解了状态机设计的特点。可以使程序结构更清晰,提高程序运行效率,更加简单易读。另外,程序中多个进程同时进行,使我们更加理解了硬件的执行方式,什么是并行执行。本次是实验小组成员共同讨论的成果,从思路的提出,具体的设计,问题的调试,每个人都提出了自己的看法,使得程序更加完善,效率更高。同时,提高了我们的团队合作意识,在实验设计过程中,我们得到了很多工作经验。

15

数字逻辑与数字系统课程设计

对于每个时间状态,我们用了4个计数器,使得代码效率有一定的降低。

十、实验分工

实验调试由全体成员完成,其中计数器模块主要由马钊和袁泉负责,状态转移模块主要由罗亚群和杨晨笛负责。

16

数字逻辑与数字系统课程设计

实验四:电子钟设计

一、实验目的

(1)掌握复杂的逻辑设计和调试

(2)学习用原理图+VHDL语言设计逻辑电路。

(3)学习数字电路模块层次设计。

(4)掌握ispLEVER软件的只用方法。

(5)熟悉ISP器件的使用

二、实验所用器件和设备

在系统可编程逻辑器件ISP1032 一片

示波器 一台

万用表或逻辑笔 一只

TEC-5实验系统,或TDS-2B数字电路实验系统 一台

三、实验内容

(1)设计并用ISP1032实现一个电子钟。电子钟具有下述功能:

a) 试验台上的6个数码管显示时、分、秒。

b) 能使电子钟复位(清零)。

c) 能启动或者停止电子钟运行。

d) 再电子钟停止运行状态下,能够修改时、分、秒的值。

e) 具有报时功能,整点时喇叭鸣叫。

(2)要求整个设计分为若干模块。顶层模块用原理图设计,底层模块用VHDL语言设计。

(3)在试验台上调试设计。

数字逻辑实验报告马钊袁泉杨晨笛罗亚群

图4-1 电子钟设计框图

四、设计思路

(1)首先完成时钟各组成计数器的设计,最基本的为1s计时器,通过对5KHZ时钟信号二分频得到,构成了整个时钟的计时基础。其次由于时钟的分和秒为60进制,小时为24进制,故完成60和24进制的计数器。

(2)将各计数器按顺序组合构成基本的时钟系统,并将得到的相应的时、分、秒信号与对应的输出相连,最后通过数码管显示。

17

数字逻辑与数字系统课程设计

(3)完成了基本的时钟系统后,加入相应的控制信号,首先是清零信号,采用了电平的触发方式,高电平清零,低电平正常工作。其次是调表控制信号,采用了2—4译码器:“00”为正常工作状态,“01”状态下对小时进行修改,“10”状态下对分钟进行修改,“11”状态下对秒进行修改。其中采用信号上升沿触发的方式进行状态的转换,并采用相同的方式对时钟的数值进行修改。

(4)最后,完成报时功能,通过分钟向小时的进位来产生响铃的控制信号,此信号持续一分钟,为了避免响铃时间过长,将响铃时间控制在10s。此外,为了打到特定的响铃效果,响铃进程采用了50KHZ的时钟信号控制响铃的音调,并将其二分频以提高响度。

五、设计方案

数字逻辑实验报告马钊袁泉杨晨笛罗亚群

LIBRARY ieee;

USE ieee.std_logic_1164.all;

USE ieee.std_logic_unsigned.all;

--------------------------------------时钟主体部分--------------------------------------

ENTITY clock is

port(clk,clr,adj,clk1 : in std_logic; --clk为5KHZ的时钟信号,clr为清零信号,adj为置数脉冲,

clk1为以50KHZ时钟信号控制响铃

choice : in std_logic; --用来选择时钟状态的脉冲信号 lighthour : out std_logic_vector(10 downto 0);

lightmin : out std_logic_vector(7 downto 0);

lightsec : out std_logic_vector(7 downto 0); --对小时,分钟和秒的输出信号 ring : out std_logic); --响铃信号

attribute LOC : string;

attribute LOC of RING : signal is "p74";

attribute LOC of CHOICE : signal is "p54";

attribute LOC of LIGHTHOUR : signal is "p9 p41 p6 p8 p12 p68 p5 p60 p10 p52 p56";

attribute LOC of LIGHTMIN : signal is "p32 p48 p33 p79 p18 p70 p46 p83";

attribute LOC of LIGHTSEC : signal is "p4 p14 p75 p37 p71 p47 p50 p29";

attribute LOC of CLK : signal is "p20";

attribute LOC of CLK1 : signal is "p82";

attribute LOC of ADJ : signal is "p15";

attribute LOC of CLR : signal is "p39"; --锁定管脚

end clock;

-------------------------------------时钟的结构体部分-------------------------------------

ARCHITECTURE behavioral of clock is

component counter_60

port(clock : in std_logic;

clk_1s : in std_logic;

adjust : in std_logic;

clr : in std_logic;

18

数字逻辑与数字系统课程设计

load : in std_logic;

s1 : out std_logic_vector(3 downto 0);

s10 : out std_logic_vector(3 downto 0);

co : out std_logic);

end component; --对模60计数器的例化

component counter_24

port(clock : in std_logic;

clk_1s : in std_logic;

adjust : in std_logic;

clr : in std_logic;

load : in std_logic;

s1 : out std_logic_vector(3 downto 0);

s10 : out std_logic_vector(6 downto 0));

end component; --对模24计数器的例化

signal sec,a:std_logic; --通过2分频产生一周期1s的sec信号 signal l1,l2,l3:std_logic; --通过l1,l2,l3来判定对时,分,秒的修改

signal c1,c2:std_logic; --低位向高位的进位信号,c1为从秒向分的进位,c2为从分向时的进位 signal load:std_logic_vector(1 downto 0);

signal temp:integer range 0 to 2499;

signal temp1:integer range 0 to 95; --计数信号

signal sec_temp:std_logic_vector(7 downto 0); --对秒的暂存信号

-----------------------------------------基本时钟进程-----------------------------------------

begin

u1 : counter_60 port map (sec,sec,adj,clr,l1,sec_temp(3 downto 0),sec_temp(7 downto 4),c1); u2 : counter_60 port map (c1,sec,adj,clr,l2,lightmin(3 downto 0),lightmin(7 downto 4),c2); u3 : counter_24 port map (c2,sec,adj,clr,l3,lighthour(3 downto 0),lighthour(10 downto 4)); lightsec(7 downto 0)<=sec_temp(7 downto 0);

--3句例化语句构成了基本的时钟系统

--------------------------------------时钟的状态转换进程--------------------------------------

process (choice)

begin

if (choice'event and choice='1') then

case load is

when "00" => l1<='0'; --时钟的正常运行状态

l2<='0';

l3<='0';

load<="01";

when "01" => l1<='0'; --此状态下对小时进行修改,即l3=‘1’

19

数字逻辑与数字系统课程设计

l2<='0';

l3<='1';

load<="10";

when "10" => l1<='0'; --此状态下对分钟进行修改,即l2=‘1’ l2<='1';

l3<='0';

load<="11";

when others => l1<='1'; --此状态下对 秒 进行修改,即l1=‘1’ l2<='0';

l3<='0';

load<="00";

end case;

end if;

end process;

-------------------------------------------1s计数进程-------------------------------------------

process(clk)

begin

if (clk'event and clk='1') then

if (temp=2499) then

temp <= 0;

sec<=not sec;

else

temp <= temp+1;

end if;

end if;

end process; --基本1s二分频计数器

---------------------------------------------响铃进程--------------------------------------------

process(clk1)

begin

if(clk1'event and clk1='1') then

if (temp1=95) then

temp1<=0;

a<=not a;

else

temp1<=temp1+1;

end if;

end if;

end process;

20

数字逻辑与数字系统课程设计

ring<=a when (c2='1' and sec_temp<10 and sec='1') else

'0';

end behavioral;

--通过sec的控制产生间断的整点响铃,铃声为高音1

数字逻辑实验报告马钊袁泉杨晨笛罗亚群

use IEEE.STD_LOGIC_1164.ALL;

use IEEE.STD_LOGIC_UNSIGNED.ALL;

----------------------------计数器主体部分----------------------------

entity counter_60 is

port (clock : in std_logic; --计数信号,即低位的进位信号或时钟脉冲信号 clk_1s : in std_logic; --周期1s的时钟信号

adjust : in std_logic; --调表置数信号

clr : in std_logic; --清零信号

load : in std_logic; --判定信号,判定当前计数器是否处于被修改状态 s1 : out std_logic_vector(3 downto 0); --计数器的个位输出(4位)

s10 : out std_logic_vector(3 downto 0); --计数器的十位输出(4位)

co : out std_logic --本位向高位进位信号

);

end counter_60;

--------------------------计数器的结构体部分--------------------------

architecture behavioral of counter_60 is

signal s1_temp: std_logic_vector(3 downto 0); --计数器的个位暂存信号

signal s10_temp : std_logic_vector(3 downto 0); --计数器的十位暂存信号

signal clk,co_temp : std_logic; --脉冲控制信号

------------------------------------------------------------------

begin

clk<=clock when load='0' else

adjust;

--通过脉冲控制信号来控制当前正常运行或调表置数 -----------------------------模60计数进程-----------------------------

process (clk,clr)

begin

if (clr='1') then

21

数字逻辑与数字系统课程设计

s1_temp <= "0000";

s10_temp <= "0000";

elsif (clk'event and clk='1')then

if (s1_temp=9) then

s1_temp <= "0000";

if (s10_temp=5) then

s10_temp <= "0000";

co_temp<='1';

else

co_temp<='0';

s10_temp <= s10_temp+1;

end if;

else

co_temp<='0';

s1_temp <= s1_temp+1;

end if;

end if;

end process;

--------------------------------输出及显示--------------------------------

s1 <= s1_temp when (clk_1s='1'or load='0') else

"1111";

s10 <= s10_temp when (clk_1s='1' or load='0') else

"1111";

--通过1s时钟信号来控制在调表状态下 对应的输出灯管 进行闪烁

co <= co_temp when (load='0') else

'0';

--当计数器处于被修改状态时不产生进位 end behavioral;

数字逻辑实验报告马钊袁泉杨晨笛罗亚群

use IEEE.STD_LOGIC_1164.ALL;

use IEEE.STD_LOGIC_UNSIGNED.ALL;

--------------------------------计数器主体部分--------------------------------

entity counter_24 is

port(clock : in std_logic; --计数信号,即低位的进位信号

22

数字逻辑与数字系统课程设计

clk_1s : in std_logic; --周期1s的时钟信号

adjust : in std_logic; --调表置数信号

clr : in std_logic; --清零信号

load : in std_logic; --判定信号,判定当前计数器是否处于被修改状态 s1 : out std_logic_vector(3 downto 0);--计数器的个位输出(4位)

s10 : out std_logic_vector(6 downto 0));--计数器的十位输出(由于需7段译码故用7位) end counter_24;

---------------------计数器的结构体部分-------------------------------

architecture behavioral of counter_24 is

signal s1_temp : std_logic_vector(3 downto 0); --计数器的个位暂存信号

signal s10_temp : std_logic_vector(1 downto 0); --计数器的十位暂存信号

signal clk : std_logic; --脉冲控制信号

---------------------------------------------------------------------

begin

clk<=clock when load='0' else

adjust; --通过脉冲控制信号来控制当前正常运行或调表置数

----------------------------模24计数进程----------------------------

process (clk,clr)

begin

if (clr='1') then

s1_temp <= "0000";

s10_temp <= "00";

elsif (clk'event and clk='1') then

if (s1_temp=3 and s10_temp=2) then

s1_temp <= "0000";

s10_temp <= "00";

elsif (s1_temp=9) then

s1_temp<="0000";

s10_temp<=s10_temp+1;

else

s1_temp <= s1_temp+1;

end if;

end if;

end process;

-----------------------------7段译码和输出显示进程-----------------------------

23

数字逻辑与数字系统课程设计

process(s10_temp)

begin

if (clk_1s='1' or load='0') then

case s10_temp is

when "00" => s10<="1111110";

when "01" => s10<="0110000";

when "10" => s10<="1101101";

when others => null;

end case;

else

s10<="0000000";

end if;

end process;

s1 <= s1_temp when (clk_1s='1' or load='0') else

"1111";

--通过1s时钟信号来控制在调表状态下 对应的输出灯管 进行闪烁 end behavioral;

六、调试中出现的问题及解决方法

由于前面已经有过很多编写计数器的经验,因此在编写计数器的方面进行的很顺利,并未遇到什么问题,但在对时钟功能的实现方面,遇到了一些问题。

(1)关于修改时钟数值的问题。开始的时候考虑用开关直接向时钟置数,此时时钟处于停止工作状态。但遇到了很多问题,首先当采用开关置数后大大占用了芯片的模块,导致后期编写控制信号时所使用的模块数受限,其次,置数的时候由于是电平触发,会产生毛刺,造成置数系统的跳动和不稳定。状态转换也遇到了相同的问题,因此最后采用了上升沿触发的方法,将置数信号以及状态控制信号都与电键相接,避免了毛刺的产生,保证了系统的稳定。

(2)关于进位问题。刚开始的时候并未对进位进行认真的考虑,后来发现当时钟处于被修改状态时,即对时、分、秒的值进行修改时,不应产生进位,故在进位信号的产生处添加了一个load控制信号,用来判定此时时钟是否处于被修改状态,若是,则不产生进位,反之,则产生进位。co <= co_temp when (load='0') else '0';

(3)关于时钟计时问题。最初的时候,按照从前数字逻辑老师讲过的60进制计数器,进位方法如下:co <= ‘1’ when ( s10_temp=5 and ts1_temp=9) else ‘0’;即当数到59的时候就立即进位,虽然是60进制的计数器,但却在59的时候立即进位造成响铃的时候会提前一分钟,后来考虑在分钟为“00000000”的时候响铃,但此时秒位可能不是全零而导致不是整点也会报时,而当把分钟与秒钟都作为判定条件时会造成模块数不足。故最后决定修改计数器,将进位信号放到计数过程中,即

if (s1_temp=9) then

s1_temp <= "0000";

if (s10_temp=5) then

s10_temp <= "0000";

co_temp<='1';

else

co_temp<='0';

24

数字逻辑与数字系统课程设计

s10_temp <= s10_temp+1;

end if;

else

co_temp<='0';

s1_temp <= s1_temp+1;

end if;

此时,计数器在记到60的时候进位,既满足了实际情况的要求,同时使响铃正常。

(4)让显示闪烁的问题。由于考虑到置数的时候需要停表,故开始时将置数信号也作为1s时钟

计数器的控制信号,但由于调表状态下输出信号的闪烁是靠1s时钟计数器来控制的,故导致了在置数状态下观察不到期望的闪烁,因而最后将闪烁的控制信号放在控制输出信号上,即:s1 <= s1_temp when (clk_1s='1'or load='0') else "1111"; 这样虽然在调表的时候时钟依然走,但更加符合现实中电子钟的构造。

(5)响铃音效问题。开始时为了避免再添加多余的接口,将1s计数器用于时钟的音效控制上,

但由于其频率实在过于低,总得不到预期的效果,故最终大家决定再用一个50KHZ的时钟信号。

七、层次设计的体会

这次实验采用层次设计主模块用来整合两个子模块60和24计数器形成基本的时钟系统。有三个底层模块:一个模块为60计数器模块,一个为24计数器模块,最后一个为响铃模块。

利用层次设计的方法,结构明了、思路清晰、便于分析。并且将复杂问题简单化、模块化、结构

化,抽象问题具体化、简单化。特别是元件例化语句使结构功能、端口连接一目了然,可以代码复用,避免重复代码,还可以增强代码的可读性。

八、比较不同种描述方式的心得

实验中结构体的三种描述方式都用到了:数据流描述、结构描述、行为描述。数据流描述(用布尔代数描述系统的输入和输出)逻辑清晰、描述简单。结构描述(分层次描述,高层可调用低层模块)使程序模块划分清晰,便于从宏观上把握程序功能,便于整体设计。行为描述更容易把握程序对于不同输入或者信号所做的动作。根据不同情况选择不同描述方法可以使程序得到优化。

九、本次设计的收获和不足

本次设计是大家最满意的一个设计,无论是从模块的设计,还是功能的实现,以及与现实中电子

钟的拟合程度上都要高于前3次设计。同时在显示效果上也更加美观贴切。

本次试验问题虽然只有5个,但解决起来着实费了很大一般功夫,大家积极思考,激烈讨论,想出了很多好的办法,并在解决问题的过程中对代码进行了优化,通过此次设计大家对于计数器有了更深入的理解,也对于进程内外代码的执行方式和顺序有了更加深刻的认识,驾驭代码的能力也有了显著的提高。对于VHDL也有了更浓厚的兴趣。

当然本次设计也有很多不足,本次设计的不足之一是在置数状态下无法逐位清零,当给清零信号时即对时钟全体清零,其次是响铃的时间足有一分钟,开始的想法是要根据电子琴给出的频率做一段音乐,但碍于模块数量以及为了完成附加试验调试时间可能不够,故最终放弃了做音乐的打算。

十、实验分工

实验调试由全体成员完成,其中计数器模块主要由罗亚群和袁泉负责,时钟总体模块主要由马钊和杨晨笛负责。

25

数字逻辑与数字系统课程设计

实验五:药片装瓶系统设计

一、实验目的

⑴掌握较复杂逻辑的设计、调试。

⑵采用VHDL语言,或原理图+VHDL语言来设计数字系统。

⑶学习数字系统设计方法。

⑷掌握ispLEVER软件的使用方法。

⑸熟悉ISP器件的使用。

二、实验所用器件和设备

在系统可编程逻辑器件ISP1032 一片

示波器 一台

万用表或逻辑笔 一只

TEC-5实验系统,或TDS-2B数字电路实验系统 一台

三、实验内容

如图5-1左面所示,药片由输送管送入漏斗装置中,后者颈部每次只允许一粒药片掉进传送带上的瓶子里。漏斗的颈部有一个光传感器,它探测到每一粒药片后产生一个电脉冲信号。这个脉冲传送到计数器中,使其计数加1,这样在药片装入瓶子过程的任一时刻,计数器都保存着瓶子中药片数量的二进制数。这个二进制数以计数器通过并行导线传送到比较器的输入端B。

另一方面,每个瓶子中要装入的固定药片数量(例如50片)通过键盘手动设置。按键信号经过编码器编码后送到寄存器A保存,而代码转换器A将寄存器A中的BCD数变成二进制数送到比较器输入端A。

假设每个瓶子要装50粒药片,当计数器的数值达到50后,比较器的A=B输出端出现高电平,指示瓶子已装满,立即关闭漏斗颈上的阀门使药片停止下落,与此同时它使传送带移动下一个瓶子到漏斗的下面。当瓶子到达漏斗颈正下方时,传送带的控制电路产生一个脉冲信号使计数器清0,比较器A=B输出端变成低电平,打开漏斗阀门,重新开始药片滴落。

数字逻辑实验报告马钊袁泉杨晨笛罗亚群

图5-1 药片装瓶计数显示系统框图

26

数字逻辑与数字系统课程设计

结合上面的药片装瓶系统设计实例,采用VHDL设计,并用ISP1032E大容量器件实现如图5-2所示的药片装瓶系统。

⑴实验台上的5个数码管作为显示系统,显示每瓶药片及总药片的数量。

⑵用实验台的红绿发光二极管来模拟对机电装置系统的输出,绿色灯亮表示启动机电装置,装瓶进行中;红色灯亮表示装瓶完成,机电装置关闭。

⑶输入子系统为包括BCD码每瓶装药数输入与装瓶开始脉冲输入,设计要求每瓶最大药片数50粒,最多装18瓶。

⑷启动装瓶开始脉冲后,如果输入数量超出最大装瓶数或者为零,要求显示系统出现告警提示。 ⑸漏斗感应器送来的药片装瓶信号用2s信号模拟,可以用实验台提供的5kHz的时钟分频产生。 ⑹在实验台上调试设计。

数字逻辑实验报告马钊袁泉杨晨笛罗亚群

图5-2 药片装瓶系统

四、设计思路

图5-3示出了药片装瓶控制与显示系统的组成总框图,它可以划分为如下七个子系统:

数字逻辑实验报告马钊袁泉杨晨笛罗亚群

图5-3 药片装瓶控制数字系统总框图

27

数字逻辑与数字系统课程设计

(注:我们在进行设计时根据实验设备的实际情况,对各子系统的具体实现方法与功能进行了调整,以下描述可能与图5-3有差异。)

输入子模块 由两个单脉冲开关和3-8译码器组成,输入子系统用来设置每个瓶子中应装的药片数和总的药瓶数。单脉冲开关Ⅰ用来切换状态(用3位二进制数状态编码),译码结果用来选择5种状态:置每瓶的药片数(十位、个位),总的药瓶数(十位、个位),系统就绪可以运行。单脉冲开关Ⅱ用来加1置数。

输出子模块1 用来显示用户设定的每个瓶子中所装的药片数和总的药瓶数。由于用七段数码管进行显示(已内置七段译码器),寄存器输出直接送数码管显示。数码管的输入来自寄存器RA和RB,RA保存用户设定的每瓶药片数的BCD码,RB保存用户设定的总药瓶数的BCD码。

输出子模块2 (与输出子系统1复用数码显示管)用来显示当前药瓶的药片数和多个瓶子中所装的药片总数值。数值分别放在计数器RC和RD中,由于均采用十进制BCD码计数,输出可直接送数码管显示。

输出子模块3 用来标识系统所处状态并且对错误输入报警。状态寄存器和报警信号的输出可直接送红、绿、黄指示灯显示。

比较子模块 由寄存器RA和计数器RC,寄存器RB和计数器RE组成。其中计数器RE用来计数已装药瓶的个数。

计数器子模块 由计数器RC、RD、RE组成。

五、设计方案

library ieee;

use ieee.std_logic_1164.all;

use ieee.std_logic_unsigned.all;

entity yaoping is

port ( start : in std_logic; --start 信号控制系统状态 0为输入状态,1为工作状态

clk : in std_logic; --clk为频率为5kHz脉冲信号

choice :in std_logic; --choice为选择输入类型脉冲

adj : in std_logic; --adj为置数脉冲,一个脉冲表示当前置数位的数加1

pill_light : out std_logic_vector(7 downto 0); --当前该瓶的装药数

total_light : out std_logic_vector(11 downto 0); --当前已装药片总数

red : out std_logic; --系统处于输入药片或药瓶状态

green : out std_logic; --系统处于装瓶状态

wrong : out std_logic --输入药瓶或药片数量不满足要求,出现告警指示

);

end yaoping;

architecture behavioral of yaoping is

signal temp :std_logic_vector(3 downto 0);--临时记录输入的数

signal temp1: integer range 0 to 9999; --产生2s信号时计数

signal temp2: integer range 0 to 2499; --产生1s闪烁信号时计数

signal onepill,clk_1s: std_logic;--onepill为2s信号,clk_1s为1s的二分频信号

signal state: std_logic_vector(2 downto 0); --输入的状态

signal pill_in,pill :std_logic_vector(7 downto 0);--pill_in每瓶药片数,pill该瓶已装数

signal total :std_logic_vector(11 downto 0); --当前已装药片总数

28

数字逻辑与数字系统课程设计

signal bottle_in, bottle: std_logic_vector(7 downto 0);--bottle_in需要瓶数,bottle已装瓶数 begin

red<=not start;

green<=start;

process(clk) --产生2s信号和1s闪烁信号的计数器

begin

if(clk'event and clk='1') then

if(temp1=9999 and start='1') then

temp1<=0;

onepill<='1';

elsif(start='1') then

temp1<=temp1+1;

onepill<='0';

end if;

if (temp2=2499) then

temp2<=0;

clk_1s<=not clk_1s;

else

temp2<=temp2+1;

end if;

end if;

end process;

process(choice) --状态转移

begin

if (choice'event and choice='1') then

case state is

when "000" => state<="001"; --000状态不置数

when "001" => state<="010"; --001状态置每瓶药片数的十位 when "010" => state<="011"; --010状态置每瓶药片数的个位 when "011" => state<="100"; --011状态置装瓶总数的十位 when others => state<="000"; --011状态置装瓶总数的个位 end case;

end if;

end process;

process(adj) --来一个adj脉冲,当前置数位的数加1

begin

if (adj'event and adj='1') then

if (temp="1001") then

temp<="0000";

else

29

数字逻辑与数字系统课程设计

temp<=temp+1;

end if;

end if;

end process;

process(temp) --将置入的数显示在显示系统上

begin

if(state="001") then

pill_in(7 downto 4)<=temp;

elsif(state="010") then

pill_in(3 downto 0)<=temp;

elsif(state="011") then

bottle_in(7 downto 4)<=temp;

elsif(state="100") then

bottle_in(3 downto 0)<=temp;

end if;

end process;

--------------------------------------------显示当前药瓶的已装片数的十位

pill_light(7 downto 4)<=pill_in(7 downto 4) when (start='0' and clk_1s='1' and state="001") else

"1111" when (start='0' and clk_1s='0' and state="001") else

pill_in(7 downto 4) when (start='0') else

pill(7 downto 4);

--------------------------------------------显示当前药瓶的已装片数的个位

pill_light(3 downto 0)<=pill_in(3 downto 0) when (start='0' and clk_1s='1' and state="010") else

"1111" when (start='0' and clk_1s='0' and state="010") else

pill_in(3 downto 0) when (start='0') else

pill(3 downto 0);

--------------------------------------------显示已装药片总数的百位

total_light(11 downto 8)<=bottle_in(7 downto 4) when (start='0' and clk_1s='1' and state="011") else

"1111" when (start='0' and clk_1s='0' and state="011") else

bottle_in(7 downto 4) when (start='0') else

total(11 downto 8);

--------------------------------------------显示已装药片总数的十位

total_light(7 downto 4)<=bottle_in(3 downto 0) when (start='0' and clk_1s='1' and state="100") else

"1111" when (start='0' and clk_1s='0' and state="100") else

bottle_in(3 downto 0) when (start='0') else

30

数字逻辑与数字系统课程设计

total(7 downto 4);

--------------------------------------------显示已装药片总数的个位

total_light(3 downto 0)<="1111" when (start='0') else

total(3 downto 0);

process(onepill) --药片装瓶系统

variable finish,c:std_logic;

--finish是否完成装瓶任务,0为未完成,1为完成;c表示当前瓶是否完成,0为未 完成,1为完成

begin

if (onepill'event and onepill='1' and finish='0') then

----------------------------------------------------------------

if (bottle/=bottle_in) then --当前装瓶数不等于输入的总瓶数

finish:='0';

else

finish:='1';

end if;

---------------------------------------------------------------

if (pill=pill_in and finish='0') then --当前该瓶已装满

pill<="00000000";

c:='1';

if (bottle(3 downto 0)="1001") then

bottle(3 downto 0)<="0000";

bottle(7 downto 4)<=bottle(7 downto 4)+1;

else

bottle(3 downto 0)<=bottle(3 downto 0)+1;

end if;

elsif (pill(3 downto 0)="1001" and finish='0') then --当前药瓶未装满且片数个位是9

pill(3 downto 0)<="0000";

pill(7 downto 4)<=pill(7 downto 4)+1;

c:='0';

elsif (finish='0') then --当前药瓶未装满且片数个位不是9

pill(3 downto 0)<=pill(3 downto 0)+1;

c:='0';

end if;

---------------------------------------------------------------

if (total(3 downto 0)="1001" and finish='0' and c='0') then --记录已装的总药片数

total(3 downto 0)<="0000";

if (total(7 downto 4)="1001") then

total(11 downto 8)<=total(11 downto 8)+1;

total(7 downto 4)<="0000";

else

total(7 downto 4)<=total(7 downto 4)+1;

31

数字逻辑与数字系统课程设计

end if;

elsif(finish='0' and c='0') then

total(3 downto 0)<=total(3 downto 0)+1;

end if;

---------------------------------------------------------------

end if;

end process;

process(pill_in,bottle_in) --输入不在要求范围内,出现告警指示

begin

if(pill_in="00000000" or pill_in>"01010000" or bottle_in="00000000" or

bottle_in>"00011000") then

wrong<='1';

else

wrong<='0';

end if;

end process;

end behavioral;

六、调试中出现的问题及解决方法

这次实验总体设计思路和模块划分很清晰,但是在具体模块的功能实现上遇到了一些问题。 ⑴ 用户如何设定每瓶的药片数和总的药瓶数?开始我们选用开关K1~K9,并用十-二优先编码器

实现。后来,我们觉得开关并不能真实模拟数字键盘,以至于输入比较繁琐,不方便使用。我们受到电子钟的启示,利用两个单脉冲开关,一个选择所置位数,另一个进行加1置数,既方便使用,又方便观察。

⑵ 需要显示的内容太多,有用户设定的每瓶药片数、总的药瓶数,还有系统运行过程中当前药

瓶已装的药片数、已经装瓶的药片总数,加起来总共需要9个数码显示管,而实验台只提供了6个数码显示管。我们的解决方法是将数码管进行复用,即在系统处于停止状态时用4个数码管显示用户设定的每瓶药片数、总的药瓶数,在系统处于运行状态时用5个数码管显示当前药瓶已装的药片数、已经装瓶的药片总数,运用when-else语句选择不同的向量输出至数码管,这样就解决了数码管不够用的问题。

⑶ 在起初,我们用2位二进制数表示3种状态(设定每瓶药片数,设定总的药瓶数,装药就绪),

这样的缺点是进行加1置数时过于麻烦(如果需要置99,则点按99次)。最终我们选择用3位二进制数表示5种状态(设定每瓶药片数的十位与个位,设定总的药瓶数的十位与个位,装瓶就绪),这样的话,如果需要置99,则只需点按18次。

⑷ 在告警模块中,要求瓶数>18或者每瓶药片数>50时,要求系统给出报警信号。我们开始把

判断条件写成(pill_in="00000000" or pill_in>50 or bottle_in="00000000" or bottle_in>18),这样就导致警告不正常。后来,我们意识到pill_in和bottle_in均是采用BCD码表示的,不能直接与整数比较大小,把条件改为(pill_in="00000000" or pill_in>"01010000" or bottle_in="00000000" or bottle_in>"00011000")后便可以正常报警了。

⑸ 当即将成功时,又出现了一个令我们迷惑了很久的问题。当装瓶结束时,装置总是多装2片

药(每瓶装满时,在下一个药片到来时我们对pill信号清‘1’,已装瓶数加1;当bottle=bottle_in时,停止装药片)。后来我们才意识到信号在进程中不是立即更新的,而是延迟到end process

32

数字逻辑与数字系统课程设计

时进行的!这样总是前一次的bottle值与bottle_in比较,导致延迟判断瓶数已经达到要求。然后,我们把(bottle=bottle_in)的判断放在了该进程的最前面,这样每来一片药,就先判断瓶数是否应经足够了,根据不同情况对变量finish赋值,由于变量是立即更新的,就可以用finish来控制是否继续进行装药。这样一来,应该没有问题了吧。我们想错了!

⑹ 现在的问题是每次总是多装1片药。原因我们很快就发现了,前面已经叙述过了,每装满1

瓶药时,对当前瓶内药片数清‘1’。解决办法是,把清‘1’改为清‘0’,但由此又带来新的问题,pill不计数时,total仍然计数!为此,我们又增加了一个变量作为total计数的条件。至此,问题就解决了。

⑺ 通用逻辑块GLB数量不够的问题。这个是最令我们头疼的问题。尽量减少对8位向量的各种

操作,遗憾的是,我们也不得不放弃一些较为复杂逻辑和功能的设计。

七、层次设计的体会

这次设计虽然没有具体分出几个.vhd文件来划分模块,但是模块层次划分依然清晰。

正如前面第四部分所描述的,药片装瓶系统分为输入子模块、输出子模块1、输出子模块2、输出子模块3、比较子模块、计数器子模块。自顶向下、划分模块的设计方法有利于简化设计、理清思路、明确分工。

八、比较不同种描述方式的心得

实验中结构体的三种描述方式都用到了:数据流描述、结构描述、行为描述。数据流描述(用布尔代数描述系统的输入和输出)逻辑清晰、描述简单。结构描述(分层次描述,高层可调用低层模块)使程序模块划分清晰,便于从宏观上把握程序功能,便于整体设计。行为描述更容易把握程序对于不同输入或者信号所做的动作。根据不同情况选择不同描述方法可以使程序得到优化。

九、本次设计的收获和不足

能够把补充实验实现已经是很大的成功了,但是还有一些遗憾。

最后这个实验可以算是前面4个实验的综合,是对我们一个不小的考验。写代码的过程极其顺利,但是调试过程却十分艰难,GLB数量不足成为一个最大的束缚,我们用各种方法精简逻辑才勉强通过。正是我们小组成员之间的齐心协力、不言放弃,才取得最终的成功。

但是也正是因为GLB的数量,限制了我们对原来设想功能的发挥,只是实现了实验的基本要求。

十、实验分工

实验调试由全体成员完成,其中输入模块:罗亚群,输出模块:袁泉,比较模块:马钊,计数器模块:杨晨笛。

33

数字逻辑与数字系统课程设计

附:数字逻辑与数字系统课程设计心得体会

一、 个人心得体会

07407班 马钊

通过本次试验,复习并充分学习掌握了VHDL语言,对其语法规则以及一些编程技巧有了更深入的了解,并更加熟练的掌握了计数器的编写方法。在学习数字逻辑这门课程的时候并没有在意到计数器在数字系统中的重要低位,通过这4次编程实验,更加深刻的理解到计数器是很多复杂数字系统的基本组成,没有计数器,很多数字系统的功能更难以实现。通过多次的编程,也更加重视培养严谨的编程态度,有时,只是一个小的编程疏忽就要调试很长时间,比如在编计数器的时候进位加错地方了,又比如本来应该是变量但不经过思考就定义为信号,再比如为了图方便把有些该分开的代码放到一个进程中,这些错误都在时刻的提醒着我们在编程的过程中要严谨认真切勿囫囵半片的就过去了,一个不该犯的小错误浪费的不仅是自己的时间,而是全组成员的时间,我想不光是学习数字逻辑时需这样,在学期其他课程时也应该养成这种良好的学习习惯。在实验期间,我们积极讨论,认真思考,不断解决了一个又一个出现的问题,真正的发扬了团队合作的精神,在其中体验到了实验的乐趣,既学到了很多课程方面的知识,同时培养了自身的动手能力,的确是获益良多。

二、 个人心得体会

07407班 袁泉

为期两周的数字逻辑与数字系统课程设计已经结束了,在这期间我们经历过许多挫折与喜悦,感触颇丰,获益匪浅。

毕竟已经半年没有接触过VHDL了,课程设计前不免有些“心虚”,就提前把VHDL的重要语法复习了一下,这对以后实验的顺利进行奠定了一定的基础。

简易电子琴的轻松完成使我们的信心大增,对“计数”与“分频”方法的熟练掌握也让我们在以后的几个实验中尝尽了甜头。

简易频率计的设计可谓费了一番周折。代码是在MAX+plus Ⅱ上完成以及仿真的,虽然仿真时也发现了代码中的一些错误并进行了改正,但是计数器输出波形的异常却始终困扰我们,最后不得不求助于实验台。奇迹发生了,在实验台上的实验结果完全正确!兴奋之余,我们认识到了仿真与具体硬件实验的区别:仿真只是工具,实践才是检验正确与错误的唯一方法。

在交通灯控制器的实验中,我们复习了有限状态机的设计方法。另外,软件与硬件设计思想的差别也让我们走了不少弯路,特别是语句的并行执行特点、进程中信号的延迟更新、信号的多源驱动、进程中敏感信号的选取等等。不过也正是从这个实验开始,我们渐渐的形成了硬件的思维方式。

在简易电子钟的实验中,我们又遇到了新的问题,通用逻辑块GLB(Generic Logic Block)数量不够。这种情况迫使我们简化逻辑设计。把8421码的置数改成了脉冲边沿触发设定时钟时间的方法,后者不仅方便,而且更接近于实际。后来又逐步实现了选定闪烁、整点报时功能,以最大程度的满足用户的需求。

最后,为了挑战自己,进一步巩固所学知识,运用所学知识解决实际问题,我们选择了药片装瓶系统。这个实验与电子钟的基本原理相同,其实设计起来也很简单,但是受限于所使用的ispLSI1032E只有32个通用逻辑块,而代码中需要大量的向量(std_logic_vector)大小比较等判断,我们只是在基本要求之上略微扩展了一下,没有实现本来设想的稍复杂的功能,这也是我们稍有遗憾之处。

完成了这5个VHDL设计之后,总算可以松一口气,仔细总结一下了。

总的来说,课程设计给了我们一次理论联系实际的机会,让我们认识到所学知识是可以应用到实

34

数字逻辑与数字系统课程设计

际生活中的。在学习VHDL时,只是感到它很高深、很强大、很遥远,从来就没有想到它可以实现如此接近生活的功能。是这次课程设计提高了我们对硬件学习和进一步研究的热情和兴趣。

除此之外,很重要的一点是,课程设计很好的培养了我们团队分工合作与配合、交流与沟通的能力。在当今社会,团队精神是是衡量一个团队竞争力的重要因素。团队成员的激烈讨论能碰撞出灵感,团队成员的齐心协力能事半功倍。我认为,经过两个星期的磨合,我们的小组成员已经凝聚成了这样一个值得我们每一位成员骄傲与自豪的团队。

另外,这次课程设计培养了我们严谨认真、耐心细致的实验态度,提高了我们发现问题、查找原因、解决问题的科学实验能力。简单的电子琴、频率计,我们不轻视;复杂的交通灯、电子钟、药片装瓶,我们也不畏惧。我们仔细推敲每一个模块,每一条语句,以避免最后调试因一个小错误而带来的不必要的麻烦。发现问题时,我们仔细思考可能引起错误的细节,然后逐一的排除,最后锁定“症结”,而不是无目的的“胡医乱医”,再把“瞎子治瘸了”。我们总结经验,以避免重蹈覆辙。

这次课程设计给了我们一个体会设计到产品的过程。产品的对象是用户,只有满足用户的需求、方便用户的使用的产品才是符合市场需求的的产品。我们在进行课程设计时,时刻从用户的角度考虑问题,不断改进着实验方案以符合实际、方便使用、正确稳定。

当然,此次课程设计的收获远不止这些,还包括意志品质方面的锻炼。当我们面对电脑屏幕经过五六个小时的思考已是脑中一片空白时,我们坚持住了,没有放弃,一个个难题就这样被我们击破。

这次课程设计可以算是一个完整的科学研究过程,体系结构实验室为我们提供了一个优秀的实验平台与实验环境,我们也充分利用了这些资源,在炎热的六月收获着知识与喜悦。相信这次课程设计将成为我们大学生活中一段美好的回忆,它对我们的影响将使我们受益终生。

三、 个人心得体会

07407班 杨晨笛

本学期的数字逻辑与数字系统课程设计让我学到了不少东西,不只是课内的关于在系统可编程以及VHDL语言的,也有对组队合作完成一项工程或设计的感受。

这次课程设计一共五道题,要求用VHDL语言设计,上一学期初步接触了VHDL语言,但只是做了一些简单的原理性的实验,这学期主要都是设计性的,使我更加深入了解了VHDL语言,以及怎样采用ISP可编程器件实现程序。

首先我们小组完成了简易电子琴的设计,回忆起了VHDL的一些基本知识,如VHDL的基本结构、语法要点、设计技巧,什么是进程,有些语句如if…else,case…when等只能在进程中使用。并行行为是描述硬件最基本的本质特性,在设计程序过程中,开始有很多次我们都受到了软件程序设计的影响,总是认为硬件的程序也是顺序执行的,有的时候想不明白程序如何一次又一次的执行的。后来对于使用进程越来越熟练,我慢慢理解了硬件程序并行执行行为。同时,也掌握了ISP器件的设计流程和编程方式,把自己编写的程序下载到硬件,让硬件去执行想要的内容,当通过波动开关产生一首简单的乐曲,是一件很奇妙的事情。

第二个实验是设计简易频率计,我们首次尝试了元件例化语句的应用,对VHDL的理解与应用又上了一个不小的台阶。元件例化语句对于代码的重用性有很大作用,可以使得程序更精简,效率却更高。

第三个交通灯实验,我们用到了枚举类型数据格式结合CASE语句实现状态机设计,了解了状态机设计的特点。可以使程序结构更清晰,提高程序运行效率,更加简单易读。后面几个实验因为比较复杂,我们设计过程中都遇到的一些奇怪的问题,调试过程比代码编写要更麻烦。这次实验设计我最深的体会,就是对于一段程序,怎样发现其中的问题和BUG,更重要的是怎么样解决问题。例如,在交通灯系统运行过程中,我们发现同一个状态的时间是不稳定的,如5s状态可能只进行了2s就跳到下一个状态。解决方法是:控制信号使计数器停止工作时(即状态转移使en=0),将进位信号c和计数

35

数字逻辑与数字系统课程设计

的temp都清零。几个实验还有一些共同的问题,通用逻辑块GLB数量不够,使得我们必须寻找更精简的方法达到同样的目的。我们采用的方法是减少向量的使用,转而使用控制信号。

这次实验设计的体会不只是课内的,团队合作意识的提高也是我这两周的很深的感受。怎样在短时间内共同完成一项任务,分工和配合是最重要的。遇到每一个问题,小组成员都会开会讨论,每个人说出自己的一些建议,逐步尝试,一步一步找到解决的方法。也许以后的工作模式也会是这样的,我们现在积累了一些这方面的知识,对以后真正进入社会我相信会有很大帮助。

当然,设计过程还有一些遗憾,不是最完美的。比如药片装瓶系统的设计,我们只是完成了基本要求,对于药瓶总数和每瓶的药片数的置数还有一些瑕疵。有的是时间问题,也有的是因为GLB数量不足,限制了我们的发挥。但是总的来说,还是相当不错的。

课程综合设计是理论与实践的统一,提高了我们的研究能力,团队精神。对于每个实验的目的,我认为我们都达到了。在以后的学习,研究,工作中,我们都有更大的信心去完成更难的任务。

四、 个人心得体会

07407班 罗亚群

为了对程序有更好地把握,不仅复习了一学期前所学习的VHDL的知识,更在此基础上扩宽了对VHDL的理解和认识,学到了更多的知识。最重要的,是体会到了学以致用的乐趣。

另外,对在系统编程了设计流程也有了一定的掌握,对ISP器件的使用也有一定的熟悉。作为一个开始的基础实验,学到的东西还是挺多的。

36

相关推荐