数字电路综合实验报告
班 级:
姓 名:
班内序号:
学 号:
日 期:
目录TOC \o "1-3" \h \u
30779 一、实验摘要 3
2634 二、实验任务 3
13164 1.任务要求 3
4997 2.任务解析 3
13415 三、实验设计思路 4
21293 1.状态转移图 4
25546 2.流程图 5
22418 3.模块确定 5
1551 4.系统框图 7
11535 四、程序代码 7
28891 ⒈主程序 7
19071 ⒉分频模块 9
8235 ⒊防抖模块 10
16981 ⒋交通灯控制模块 11
20860 ⒌数字译码模块 14
25988 五、实验结果 15
15778 1.仿真结果 15
11930 2.实物结果 17
3563 六、所遇问题分析 17
16058 七、实验总结 18
交通灯控制器的VHDL实现
一、实验摘要
随着交通情况的日益复杂,交通灯在生活中所处的位置也越来越高。本实验就是基于VHDL语言编程实现了十字路口的交通灯控制器。对于交通等控制器的设计是分模块自顶向下的设计思想,软硬件结合来实现本设计。
关键字:交通灯、VHDL、控制器
二、实验任务
1.任务要求
南北和东西方向各有一组绿、黄、红灯用于指挥交通,绿灯、黄灯和红灯的持续时间分别为20秒、5秒和25秒;
当有特殊情况(如消防车、救护车等)时,两个方向均为红灯亮,计时停止,当特殊情况结束后,控制器恢复原来状态,继续正常运行;
用两组数码管,以倒计时方式显示两个方向允许通行或禁止通行的时间;
2.任务解析
东西(A车道)和南北(B车道)方向各有一组绿、黄、红灯用于指挥交通(如图1),绿灯、黄灯和红灯的持续时间分别为 20 秒、5 秒和 25 秒。
图1 十字路口交通灯模型
因此,可以设计如下四个状态,其关系为:
状态
亮灯情况
车辆行驶状况
持续时间(秒)
下一状态
A车道
B车道
S0
红亮
红亮
紧急状况,A/B车道均禁止通行
~
S1
S1
绿亮
红亮
A车道通行,B车道禁止通行
20
S2
S2
黄亮
红亮
A车道缓行,B车道禁止通行
5
S3
S3
红亮
绿亮
A车道禁止通行,B车道通行
20
S4
S4
红亮
黄亮
A车道禁止通行,B车道缓行
5
S1
三、实验设计思路
1.状态转移图
图2 状态转移图
2.流程图
图3 流程图
3.模块确定
⑴分频模块
设计原因:由于实验板只能提供50MHz的时钟信号,而电路中只能使用较低频率的时钟:
1Hz时钟信号:计数器count变化时使用;
20Hz时钟信号:在防抖电路中使用的时钟信号;
1kHz时钟信号哦:用于数码管位选信号的改变的时钟信号。
功能:用于将实验板上的50MHz的时钟信号经分频后输出:1kHz、20Hz、1Hz。
图4 分频模块的输入和输出
⑵防抖动模块
设计原因:只要有按键或是拨码开关,防抖电路就是不可缺少的一个模块。否则,按键信号中的一些毛刺和抖动往往会引起电路不可预知的错误。
功能:将带有抖动的信号进行识别和判断,输出持续时间超过0.1s的高电平信号。
图5 防抖动模块的输入和输出
⑶交通灯控制模块
设计原因:这个模块是本程序设计的灵魂,是重中之重!这个模块用于控制电路的状态改变和按键响应,也就是系统中控制器的作用。
功能:根据按键信号和输入时钟,输出符合交通灯状态变化规律的LED驱动信号、数码管显示的数据、数码管位选信号。
图6 交通灯控制模块的输入和输出
⑷数字译码模块
设计原因:由于交通灯控制模块输出的为数码管显示的数据,为10进制数,因此必须要一个译码电路,将此十进制数转化为LED灯的驱动信号,而这个功能正是由此模块完成。
功能:将输入的十进制数转变为相应的8位2二进制数作为数码管的驱动信号。
图7 数字译码模块的输入和输出
⑸整体模块连接图
图8 模块整体连接图
4.系统框图
图9 系统框图
四、程序代码
⒈主程序
主程序
library ieee;
use ieee.std_logic_1164.all;
entity traffic_lights is
port(clk:in std_logic; 时钟信号
emerg,reset:in std_logic; 复位和紧急情况信号
seg:out std_logic_vector(7 downto 0); 7段数码管显示
select_led:out std_logic_vector(5 downto 0); 选通输出
lights:out std_logic_vector(7 downto 0));led发光管输出
end traffic_lights;
architecture a of traffic_lights is 分别调用各个模块
signal cp1k,cp20,cp1,resetout,emergout:std_logic;
signal number:integer range 0 to 9;
component freq_divide 分频模块 1k 100hz 1hz
port(clk_in:in std_logic;
clk_1,clk_20,clk_1k:out std_logic);
end component;
component noshake 分频模块 1k 100hz 1hz
port(clk_20,keyin:in std_logic;
keyout:out std_logic);
end component;
component traffic 交通灯控制模块
port(clk1,clk1k:in std_logic;
emerg,reset:in std_logic;
num:out integer range 0 to 9;
lights:out std_logic_vector(7 downto 0);
select_led:out std_logic_vector(5 downto 0));
end component;
component display 数字译码模块
port(num:in integer range 0 to 9;
seg:out std_logic_vector(7 downto 0));
end component;
begin
u1:freq_divide port map(clk,cp1,cp20,cp1k); 分频器产生时钟信号
u2:noshake port map(cp20,reset,resetout); 对复位信号防抖处理
u3:noshake port map(cp20,emerg,emergout); 对紧急信号防抖处理
u4:traffic port map(cp1,cp1k,emergout,resetout,number,lights,select_led); 状态机运转
u5:display port map(number,seg); 数码管显示
end;
⒉分频模块
分频模块
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity freq_divide is
port(clk_in : in std_logic;
clk_1,clk_20,clk_1k : out std_logic);
end;
architecture a of freq_divide is
signal count1 : integer range 0 to 24999;
signal count2 : integer range 0 to 24;
signal count3 : integer range 0 to 9;
signal clk_tmp1,clk_tmp2,clk_tmp3: std_logic;
begin
50000分频进程
输出:1kHz的时钟信号
功能:用于数码管显示时刷新频率
p1:process(clk_in)
begin
if (clk_in'event and clk_in='1') then
if count1=24999 then
count1<=0;
clk_tmp1<= not clk_tmp1;
else
count1<=count1+1;
end if;
end if;
end process p1;
50分频进程
输出:20Hz的时钟信号
功能:防抖动电路中使用
p2:process(clk_tmp1)
begin
if (clk_tmp1'event and clk_tmp1='1') then
if count2=24 then
count2<=0;
clk_tmp2<= not clk_tmp2;
else
count2<=count2+1;
end if;
end if;
end process p2;
20分频进程
输出:1Hz的时钟信号
用于状态转变的时钟信号
p3:process(clk_tmp2)
begin
if (clk_tmp2'event and clk_tmp2='1') then
if count3=9 then
count3<=0;
clk_tmp3<= not clk_tmp3;
else
count3<=count3+1;
end if;
end if;
end process p3;
clk_1<=clk_tmp3;
clk_20<=clk_tmp2;
clk_1k<=clk_tmp1;
end;
⒊防抖模块
防抖动模块
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity noshake is
port(clk_20,keyin: in std_logic;
keyout: out std_logic);
end;
architecture a of noshake is
signal cp:std_logic;
begin
只有持续时间高于0.1s的高电平才有效
process(clk_20)
variable times:integer range 0 to 2;
begin
if (clk_20'event and clk_20='1') then
if keyin='1' then
if times=2 then
times:=times;
else times:=times+1;
end if;
else times:=0;
end if;
end if;
if times=2 then
cp<='1';
else cp<='0';
end if;
keyout<=cp;
end process;
end;
⒋交通灯控制模块
交通灯控制模块
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity traffic is
port(clk1,clk1k:in std_logic;
emerg,reset:in std_logic;
num:out integer range 0 to 9;
lights:out std_logic_vector(7 downto 0);
select_led:out std_logic_vector(5 downto 0));
end traffic;
architecture control of traffic is
type states is(s0,s1,s2,s3,s4);
signal state:states;
signal num1,num2,num3,num4:integer range 0 to 9;
signal emerg_status,reset_status:std_logic:='0';
signal count:integer range 1 to 50 :=50;
begin
紧急信号的处理进程
p1:process(emerg)
begin
emerg_status<=emerg;
end process p1;
复位信号处理及计数器count控制进程
p2:process(reset)
begin
reset_status<=reset;
end process p2;
p3:process(clk1)
begin
if(reset_status='1') then
count<=50;
elsif(emerg_status='1') then
count<=count;
else
if(clk1'event and clk1='1') then
if count=1 then
count<=50;
else count<=count-1;
end if;
end if;
end if;
end process;
核心状态机
p4:process(emerg_status,count)根据计数器来选择交通灯状态
begin
if(emerg_status='1')then state<=s0; 6个正常状态和1个紧急情况状态
else
if(count>=31)then state<=s1;
elsif(count<=30 and count>=26)then state<=s2;
elsif(count<=25 and count>=6)then state<=s3;
else state<=s4;
end if;
end if;
case state is 交通灯状态,用LED发光管模拟交通灯
when s0=>lights<=; --;RA/RB
when s1=>lights<=; --;GA/RB
when s2=>lights<=; --;YA/RB
when s3=>lights<=; --;RA/GB
when s4=>lights<=; --;RA/YB
end case;
end process;
根据计数器值确定数码管显示数字
p5:process(emerg_status,count)
begin
if(emerg_status='1') 紧急状态下数码管显示8
then num1<=8;num2<=8;num3<=8;num4<=8;
else
状态S1
if(count=50)
then num1<=2;num2<=0;num3<=2;num4<=5;
elsif(count>=45 and count<50)
then num1<=1;num2<=count-40;num3<=2;num4<=count-45;
elsif(count>=40 and count<=44)
then num1<=1;num2<=count-40;num3<=1;num4<=count-35;
elsif(count>=35 and count<=39)
then num1<=0;num2<=count-30;num3<=1;num4<=count-35;
elsif(count>=31 and count<=34)
then num1<=0;num2<=count-30;num3<=0;num4<=count-25;
状态S2
elsif(count>=26 and count<=30)
then num1<=0;num2<=count-25;num3<=0;num4<=count-25;
状态S3
elsif(count=25)
then num1<=2;num2<=5;num3<=2;num4<=0;
elsif(count>=20 and count<=24)
then num1<=2;num2<=count-20;num3<=1;num4<=count-15;
elsif(count>=15 and count<=19)
then num1<=1;num2<=count-10;num3<=1;num4<=count-15;
elsif(count>=14 and count<=10)
then num1<=1;num2<=count-10;num3<=0;num4<=count-5;
状态S4
elsif(count>=6 and count<=9)
then num1<=1;num2<=count;num3<=0;num4<=count-5;
else num1<=0;num2<=count;num3<=0;num4<=count;
end if;
end if;
end process;
数码管选通信号输出
p6:process(clk1k)
variable temp:integer range 0 to 3;
begin
if(clk1k'event and clk1k='1')then
case temp is
when 0=>num<=num1;temp:=1;select_led<="011111"; 选用4个数码管输出倒计时
when 1=>num<=num2;temp:=2;select_led<="101111";
when 2=>num<=num3;temp:=3;select_led<="111101";
when 3=>num<=num4;temp:=0;select_led<="111110";
end case;
end if;
end process;
end;
⒌数字译码模块
数字译码模块
library ieee;
use ieee.std_logic_1164.all;
entity display is
port(num:in integer range 0 to 9;
seg:out std_logic_vector(7 downto 0));
end;
architecture a of display is
begin
d1:process(num)
begin
case num is
when 0=>seg<=; 由七位二进制数表示0到9
when 1=>seg<=;
when 2=>seg<=;
when 3=>seg<=;
when 4=>seg<=;
when 5=>seg<=;
when 6=>seg<=;
when 7=>seg<=;
when 8=>seg<=;
when 9=>seg<=;
when others=>seg<="XXXXXXXX";
end case;
end process;
end;
五、实验结果
1.仿真结果
⑴仿真说明
由于分频模块的存在,导致无法整体仿真(可能可以,但是很费时间)。因此,只对核心模块——交通灯控制模块进行仿真。
为了结果的易读性,现将程序做如下修改。
①LED灯的驱动信号lights的修改:
when s0=>lights<=; --;RA/RB
when s1=>lights<=; --;GA/RB
when s2=>lights<=; --;YA/RB
when s3=>lights<=; --;RA/GB
when s4=>lights<=; --;RA/YB
即从S0~S4,相应的lights信号从0~4改变。
②数码管位选信号select_led的修改:
when 0=>num<=num1;temp:=1;select_led<="000000";
when 1=>num<=num2;temp:=2;select_led<="000001";
when 2=>num<=num3;temp:=3;select_led<="000010";
when 3=>num<=num4;temp:=0;select_led<="000011";
即数码管位选信号循环输出0~3。
③输入信号:1Hz和1kHz的时钟信号,仿真时间为110s。
⑵仿真波形图
①正常状况下
reset和emerg都为低电平。
图10 正常状态下的仿真波形
图11 续图10
由上两图可见,正常情况下,状态转移完全符合设计要求:,如此循环往复。
num信号和select_led信号(局部)
图12 正常运行下的的仿真波形
数码管显示数字和数码管位选信号也都正常输出。
②复位信号响应
reset信号
reset信号
图13 复位情况下的仿真波形
由上面仿真波形中可见,当reset为高电平时,在时钟沿上状态改变为S1,即复位成功。
③紧急信号响应
紧急信号
紧急信号
图14 紧急情况下的仿真波形
由图14可见,在emerg信号有效时,交通灯状态一直处于S0,一旦emerg信号失效,状态立马恢复到原来(emerg信号之前的状态)。总之,紧急状况处理成功!
2.实物结果
总体来说,实验要求的基本功能全部完成,且没有bug。交通灯运行完全符合前面分析的要求。
六、所遇问题分析
问题1:状态改变的参考量的确定。
解决方案:当初设计时,丝毫没有头绪。当参考了以前同学的程序后,心中不由豁然开朗——使用计数器count的值来控制状态改变和数码管显示数字。这个想法确实很巧妙,做到了一个count解决所有控制问题。这样的设计,大大减小了程序的复杂度。
问题2:reset信号由拨码开关还是由按键来输入。
解决方案:这点困扰了我好久。最后考虑到如果使用按键输入时,一来与实际情况不符,二来为程序编写增加了难度。难度引入主要是由于按键检测的时钟和按键状态检测的时间,都很难确定,无论使用分频器产生的何种时钟信号都无法满足要求。最后采用拨码开关直接输入,使程序大为简便,也使这一问题得到圆满的解决。
七、实验总结
这次实验中,虽然在编程中遇到了不少困难,但是最终还是按时完成实验,确实令人信心倍增啊。
首先,在实验题目选定之后,对于题目的切入点一直找不到,不知如何下手。于是就在老师的课件中找灵感,万幸的是我竟然找见了!在老师课件中的一些示例中,我慢慢摸索和品味其中的要义,认真思考硬件编程的特点,并在网上查找资料,并重新拜读了去年发的那本《数字电路实验讲义》,从中得到不少启迪。终于在第二次上课前完成了程序原理和状态分析等任务。
然后,就开始编程了。最先编写的是分频模块——按照数字电路网站上的那个50M分频器的方法,编写出了实验要求的分频模块。接下来就是编写程序的主模块——交通灯控制模块。这个模块的编写借鉴了以前同学的设计思路,因此编写的头绪时很清晰的。最后编写了防抖模块和数字译码模块。这个过程中,始终伴随我的就是编译时的各种warning和error。但是我没有泄气。要知道——兵来将挡,水来土掩;凡事皆有因。有错误,就一句一句排错,最后整体进行逻辑检测。终于在最后一个没有warning和error的程序编写完毕。
接下来就是仿真和下载。但是在仿真中,发现原先编写的程序有很大的逻辑错误。于是反复修改,反复阅读程序,查找病因。果然是“苦心人,天不负”,终于在最后,一个仿真正常、运行正常的程序编写成功。此时的喜悦真是无以言表。
在以上过程中,对于硬件编程的理解日渐深刻。这是我使我在平常的软件编写的惯性中,不由停下脚步,慢慢体会硬件编程的思想和技巧。
数字电路综合实验虽然结束了,但是在实验中学到的知识将使我收益一生。在此,感谢那些“诲人不倦”的老师和同学!
相关热词搜索: 交通灯 控制器 北邮 数字电路 实验