数字电路综合实验报告
交通灯控制器
院系:电信工程学院通信工程系 班级:0111105班 姓名:***
学号:******号(1号)
一、设计任务要求
交通灯控制器:用于十字路口的交通灯控制器。 实验要求:
1. 东西方向各有一组红,黄,绿灯用于指挥交通,红,黄,绿的持续时间分别为25s,5s,20s。 2. 当有紧急情况(如消防车)时,两个方向均为红灯亮,计时停止,当特殊情况结束后,
控制器恢复原来状态,正常工作。
3. 组数码管,以倒计时方式显示两个方向允许通行或禁止通行的时间。
二、设计思路及总体结构框图
设计思路:
1.硬件:由设计任务要求可知,总体输入电路有:
(1)在开始计时之前的等待状态,复位键reset接低电位,接通电源后,首先要将它接高电位,表示计时开始。
(2)当按一下(on_off)键,表示紧急情况发生,两个方向均为红灯亮,计时停止,当再次按下(on_off)键时,控制器恢复原来状态,正常工作。
输出电路:
(1)由于东西和南北方向都要显示时间,因此需要4个数码管,这样在设计中就需要四条输出线choose4,用来选通指定一个LED七段显示数码管。
(2)显示器的每一位都采用LED七段显示数码管进行显示,每一个LED七段显示数码管都要有七条输出线控制,一共使用4个七段数码管,故输出电路使用四个七位输出信号:showtime1,showtime2,showtime3,showtime4。
(3)东西和南北方向都有交通灯亮的情况,故输出电路中要有两个状态控制信号state1,state2分别控制东西和南北的灯,每个方向上有4个灯(增加了左、右转弯显示控制功能),所以state1,state2的类型应该是4位数组型的。
外部电路图如下: 东西方向 clk 4/ State1 交通灯 stas reset 南北方向State2 on_off 4/ 交通灯 Showtime1 7/ 7/ Showtime2 7/ Showtime3 7/ Showtime4 Choose4 4/
2.软件:
(1)在VHDL设计描述中,采用自顶向下的设计思路,该思路,首先要描述顶层的接口,上面的描述已经规定了交通灯控制的输入输出信号:
- 2 -
输入信号:复位开关信号reset;
紧急情况控制信号on_off; 外部时钟信号clk。
输出信号:LED七段显示数码管的选通信号choose4(3 downto 0);
LED七段显示数码管的输出信号showtime1(6 downto 0),showntime2(6 downto 0),showtime3(6 downto 0),showtome4(6 downto 0);
交通灯状态控制信号state1(3 downto 0),state2(3 downto 0)。
(2)在自顶向下的VHDL设计描述中,通常把整个设计的系统划分为几个模块,然后采用结构描述方式对整个系统进行描述。根据实验设计的结构功能,来确定使用哪些模块以及这些模块之间的关系。
由于紧急情况控制信号是采用按键的输入方式,其产生时刻和持续时间的长短是随机不定的,且存在因开关簧片反弹引起的电平抖动现象,因此必须在每个开关后面安排一个消抖和同步化电路模块,以保证系统能捕捉到输入脉冲,故需要有防抖动的模块。
由于外部时钟信号clk的频率为1MHz,而实际需要的内部计时时钟频率为1Hz,提供给消抖同步电路的频率为50Hz(满足按键)和提供给产生选通信号电路的时钟频率为200Hz(满足视觉暂留效应)。
当正常计时开始后,需要进行定时计数操作,由于东西和南北两个方向上的时间显示器是由两个LED七段显示数码管组成的,因此需要产生两个2位的计时信息:2个十位信号,2个个位信号,这个定时计数操作可以由一个定时计数器来完成,又因为交通灯的状态变化是在计时为0的情况下才能进行的,因此需要一个计时电路来产生使能信号,因此定时计数的功能就是用来产生2个2位计时信息和使能信号。
另外还需要将时间显示出来,为了节省资源,我采用了循环点亮LED七段显示数码管的方法来显示计时输出。通过信号choose4(3 downto 0)来对4个LED七段显示数码管进行选择。
由于不能使用7448自动译码集成电路,故在LED七段显示数码管显示时间时,要把计时结果转换为七段码输出到相应的LED七段显示数码管上,因此还需要一个转换电路。
交通灯状态控制也需要一个电路,当有使能信号及无紧急情况下,交通灯状态不发生变化,有紧急情况时,两个方向上均为红灯亮,紧急情况消除后,回到原来状态,无使能信号时,交通灯状态不变。
通过上面的分析,不难得知可以把交通灯控制系统划分为6个模块:键输入模块,时钟分频模块,计时模块,选通模块,显示模块,控制模块。各个模块之间的连接关系如下:
reset 键 入 计 时 模 转 换 模 showtime 输on_off 模块 块 块
reset0 on_off0 clk1 timel,times 选 通 模 clk2 时 钟 分 频 clk0 选通模块 choose4 块 模块
三、总体结构框图
- 3 -
No
通电 复位 yes 东西为红,南北为绿,计时开始 Yes No No 20s 计时到
Yes 东西为黄,南北为绿
No 是否有紧急情况 Yes 是否消除? Yes No
计时到5s No Yes 两方向均为红,计时停止 是否有紧急情况
东西为红,南北为绿 是否有紧急情况 Yes No
计时到20s No Yes
东西为红,南北为黄 Yes 是否有紧急情况
No 计时到5s Yes
四、分块电路设计.
(1)键输入模块(keyin)
输入信号:紧急情况on_off;用来消除抖动的时钟信号clk1,由时钟分频模块提供。
- 4 -
输出信号:去抖后的提示信号on_off0。 (2)时钟分频模块(clk_div)
输入信号:外部时钟信号clk;
输出信号:消除抖动的时钟信号clk1;计时内部时钟信号clk2;产生选通信号的时钟信号clk0。
(3)计时模块(time):
输入信号:定时计时时钟clk2,由时钟分频模块提供;去抖动后的提示信号on_off0;复位信号reset;状态提示信号state(1 downto 0);
输出信号:东西方向的十位信号eq1(3 downto 0);东西方向的个位信号eq0(3 downto 0);南北方向的十位信号sq1(3 downto 0);南北方向的个位信号sq0(3 downto 0);使能信号timel,times。 (4)选通模块(choose):
输入信号:选通时钟信号clk0,由时钟分频模块提供。 输出信号:选通信号choose4(3 downto 0)。 (5)显示模块(display):
输入信号:计时的十位或个位信号;
输出信号:控制LED七段显示数码管的七位数组型信号。 (6)控制模块(keep):
输入信号:复位信号reset;去抖后的紧急情况提示信号on_off0;定时计时时钟信号clk2;使能信号timel,times;
输出信号:东西方向交通灯状态控制信号state1(3 downto 0);南北方向交通灯状态控制信号state2(3 downto 0);交通灯状态提示信号state(1 downto 0)。 五、总体电路图(图形法).
六、仿真波形
状态变化仿真图:以下显示选通信号的仿真波形
- 5 -
七、源程序
主模块:----------traffic module--------- library ieee;
use ieee.std_logic_11.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; entity tracfic is
port(reset : in std_logic;-----------------------复位信号 clk : in std_logic;-----------------------外部时钟信号
showtime1,showtime2,showtime3,showtime4: out std_logic_vector(6 downto 0);-------------------------- 控制LED七段显示数码管的七位数组型信号 choose4 : out std_logic_vector(3 downto 0);--------选通信号 on_off : in std_logic;------------------------紧急情况控制信号
- 6 -
state1,state2 : out std_logic_vector(3 downto 0));---交通灯状态控制信号 end tracfic;
architecture system of tracfic is-----------------元件例化调用 component keyin---------------------------------去抖动模块 port(a,b:in std_logic; c :out std_logic); end component;
component time-----------------------------------计时模块 port(a,b,k:in std_logic;
c:in std_logic_vector(1 downto 0);
d,e,f,g:out std_logic_vector(3 downto 0); j,h:out std_logic); end component;
component choose --------------------------------选通模块 port(a:in std_logic;
b:out std_logic_vector(3 downto 0)); end component;
component display -------------------------------显示模块 port(a:in std_logic_vector(3 downto 0); b:out std_logic_vector(6 downto 0)); end component;
component clk_div--------------------------------时钟分频模块 port(a:in std_logic;
b,c,d:out std_logic); end component;
component keep-----------------------------------状态控制模块 port(a,b,c,g,j:in std_logic;
d,e:out std_logic_vector(3 downto 0); f:out std_logic_vector(1 downto 0)); end component;
signal on_off0:std_logic; 紧急情况经去抖后的输出信号; signal state:std_logic_vector(1 downto 0); 控制计数器的状态提示信号; signal clk0,clk1,clk2:std_logic; 时钟分频后的输出信号;
signal eq0,sq0:std_logic_vector(3 downto 0); 南北和东西计数器的个位输出; signal eq1,sq1:std_logic_vector(3 downto 0); 南北和东西计数器的十位输出; signal timel,times:std_logic; 计数器对控制器的反馈信号; begin 用信号把各个模块连起来; u1:keyin port map(clk1,on_off,on_off0);
u3:time port map(clk2,on_off0,reset,state,eq0,eq1,sq0,sq1,timel,times); u4:choose port map(clk0,choose4); u5:display port map(eq0,showtime1); u6:display port map(eq1,showtime2); u7:display port map(sq0,showtime3); u8:display port map(sq1,showtime4);
- 7 -
u9:keep port map(on_off0,timel,times,clk2,reset,state1,state2,state); u10:clk_div port map(clk,clk0,clk1,clk2); end system;
去抖模块: --------keyin module----- library ieee;
use ieee.std_logic_11.all; entity keyin is
port(A,B :in std_logic; C :out std_logic); end keyin;
architecture keyin_arc of keyin is component kand2
port(A,B :in std_logic; C :out std_logic); end component; component kdf
port(A,B :in std_logic; C,D :out std_logic); end component;
component knand2
port(A,B :in std_logic; C :out std_logic); end component;
signal TMP1,TMP2,TMP3,TMP4,TMP5,TMP6:std_logic; begin
u0: knand2 port map(A,TMP1,TMP2); u1: knand2 port map(TMP2,TMP3,TMP1); U2: kdf port map(TMP2,B,TMP4,TMP3); U3: kdf port map(TMP4,B,TMP6,TMP5); u4: kand2 port map(TMP4,TMP5,C); end keyin_arc;
library ieee; ---two inputs and gate description use ieee.std_logic_11.all; entity kand2 is
port(A,B :in std_logic; C :out std_logic); end kand2;
architecture kand2_arc of kand2 is begin
C<=A and B;
end kand2_arc;---end of two inputs and gate description library ieee; ---two inputs and_not gate description use ieee.std_logic_11.all; entity knand2 is
- 8 -
port(A,B :in std_logic; C :out std_logic); end knand2;
architecture knand2_arc of knand2 is begin
C<=not(A and B);
end knand2_arc;---end of two inputs and_not gate description library ieee; ---D trigger description use ieee.std_logic_11.all; entity kdf is
port(A,B :in std_logic; C,D :out std_logic); end kdf;
architecture kdf_arc of kdf is begin
process(B) begin
if(B'event and B='1')then C<=A;D<=not A; end if; end process; end kdf_arc;
选通模块:该模块是为节省资源而设的,实验中有四个LED七段数码管显示计数,点亮一个LED需电流5-50mA,同时点亮4个LED,CPLD可能无法负荷这样的电流驱动,而且功率太大,散热也是问题。同时这么做也容易造成电路被烧毁,因此需要逐个循环点亮。又为使显示结果持续不致闪烁抖动,只需每个扫描频率超过人眼视觉暂留频率24Hz以上,就能达到。选择200Hz作为时钟,分到4个数码管,每个数码管50Hz(大于24Hz),故不会有闪烁。 library ieee; -------choose module---------- use ieee.std_logic_11.all; use ieee.std_logic_unsigned.all; entity choose is
port(a:in std_logic;
b:out std_logic_vector(3 downto 0)); end choose;
architecture choose_arc of choose is signal m :integer range 0 to 3; begin
process(a) begin
if(a'event and a='1')then if(m=3)then m<=0; else m<=m+1; end if; end if;
case m is when 0 =>b<=\"0111\";
- 9 -
when 1 =>b<=\"1011\"; when 2 =>b<=\"1101\"; when 3 =>b<=\"1110\"; end case; end process; end choose_arc;
分频模块:实验中需要三个不同频率的时钟:消抖电路需要10Hz的时钟,选通电路需要200Hz的时钟,计时需要1Hz的时钟。外部提供的时钟的频率为1MHz,故需要经过分频得到,但由于外部时钟的频率和我们所需要的时钟的频率相差太远,一次分频到底又占用太多的资源,所以我采用的是先对外部时钟进行一定的分频,再依次向下分,得到我们需要的时钟,这样可以节省很多资源。
library ieee; -----clk_div module------- use ieee.std_logic_11.all; entity clk_div is
port(a:in std_logic;------------------------------外部时钟信号
b:out std_logic;-----------------------------频率为200Hz的时钟信号 c:out std_logic;-----------------------------频率为10Hz的时钟信号 d:out std_logic);----------------------------频率为1Hz的时钟信号 end clk_div;
architecture clk_div_arc of clk_div is signal clk_10k:std_logic; signal clk_200:std_logic; signal clk_10:std_logic; signal clk_1:std_logic;
signal m:integer range 0 to 100; signal n:integer range 0 to 50; signal l:integer range 0 to 20; signal g:integer range 0 to 10; begin
p1: process(a)-----------先对外部时钟进行100分频,得到频率为10KHz的时钟信号 begin
if(a'event and a='1')then if m=99 then m<=0; else m<=m+1; end if;
if (m<=49) then clk_10k<='0'; else clk_10k<='1'; end if; end if; end process;
p2:process(clk_10k)-------对10KHz的时钟信号再进行50分频,得到200Hz的时钟信号 begin
if (clk_10k'event and clk_10k='1')then if n=49 then n<=0;
- 10 -
else n<=n+1; end if;
if n<=24 then clk_200<='0'; else clk_200<='1'; end if; end if; end process; b<=clk_200;
p3:process(clk_200)----对200Hz的时钟信号进行20分频,得到10Hz的时钟信号 begin
if(clk_200'event and clk_200='1')then if l=19 then l<=0; else l<=l+1; end if;
if l<=9 then clk_10<='0'; else clk_10<='1'; end if; end if; end process; c<=clk_10;
p4:process(clk_10)----对10Hz的时钟信号进行10分频,得到需要的1 Hz的时钟信号 begin
if (clk_10'event and clk_10='1')then if g=9 then g<=0; else g<=g+1; end if;
if g<=4 then clk_1<='0'; else clk_1<='1';
end if; end if ; end process; d<=clk_1;
end clk_div_arc;
显示模块:------display module-------- library ieee;
use ieee.std_logic_11.all; use ieee.std_logic_signed.all; use ieee.std_logic_unsigned.all; entity display is
port(a:in std_logic_vector(3 downto 0);-------------输入记数结果
b:out std_logic_vector(6 downto 0));---------译码成七段数码管的控制信号 end display;
architecture display_arc of display is signal a0:std_logic_vector(3 downto 0); begin
- 11 -
process(a0) begin a0<=a;
case a0 is when \"0000\" =>b<=\"0111111\";---------以下是译码部分 when \"0001\" =>b<=\"0000110\"; when \"0010\" =>b<=\"1011011\"; when \"0011\" =>b<=\"1001111\"; when \"0100\" =>b<=\"1100110\"; when \"0101\" =>b<=\"1101101\"; when \"0110\" =>b<=\"1111101\"; when \"0111\" =>b<=\"0000111\"; when \"1000\" =>b<=\"1111111\"; when \"1001\" =>b<=\"1101111\"; when others=>b<=\"ZZZZZZZ\"; end case; end process; end display_arc;
控制模块:---------keep module--------- library ieee;
use ieee.std_logic_11.all; entity keep is
port( a,b,c,g,j : in std_logic;
d,e : out std_logic_vector(3 downto 0); f : out std_logic_vector(1 downto 0)); end keep;
architecture keep_arc of keep is type state_type is (s0,s1,s2,s3,s4); signal current_state:state_type; signal new_state:state_type; begin
newstate_logic:
process(current_state,b,a,g) variable m:integer range 0 to 3; begin
if(g='0')then new_state<=s1;----------------通电后给交通灯状态赋初值 else case current_state is when s1 =>m:=0;
if(b='1'and j='0'and a='0')then---当计数到20s且无紧急情况时,交通灯跳至下
一状态
new_state<=s2;
elsif(a='1')then new_state<=s0;-----有紧急情况时,交通灯变为紧急状态 else new_state<=s1;------------------计时未到的时候保持原状态不变 end if;
when s2 =>m:=1;
- 12 -
if(b='1'and j='1'and a='0')then new_state<=s3;-----当记数到5s且无紧急情
况时,交通灯变为下一状态
elsif(a='1')then new_state<=s0;------有紧急情况时,交通灯变为紧急状态 else new_state<=s2; ----------计时未到的时候保持原状态不变 end if;
when s3 =>m:=2;
if(j='1'and b='0'and a='0')then new_state<=s4;---------当记数到20s且无
紧急情况时,交通灯变为下一状态
elsif(a='1')then new_state<=s0;----有紧急情况时,交通灯变为紧急状态 else new_state<=s3; ---------------计时未到的时候保持原状态不变 end if; when s4 =>m:=3;
if(j='1'and b='1'and a='0')then new_state<=s1;----------当记数到5s且无
紧急情况时,交通灯变为下一状态
elsif(a='1')then new_state<=s0;-----有紧急情况时,交通灯变为紧急状态 else new_state<=s4; ----------------计时未到的时候保持原状态不变 end if;
when s0=>if(a='0')then-------------紧急情况消除后,回到原来状态 case m is when 0 =>new_state<=s1;
when 1 =>new_state<=s2; when 2 =>new_state<=s3; when 3 =>new_state<=s4;
end case;
else new_state<=s0; end if; end case; end if;
end process;
state_register: process(c) begin
if(c'event and c='1')then current_state<=new_state;-------当时钟上升沿触发时,
交通灯状态发生改变
end if; end process; output_logic:
process(current_state)-----产生与交通灯状态相对应的提示信号,以控制计时模块的不
同状态下的不同赋植
begin
case current_state is when s0 => d<=\"0100\";e<=\"0100\"; when s1 => d<=\"0100\";e<=\"1001\";f<=\"00\"; when s2 => d<=\"0100\";e<=\"0010\";f<=\"01\"; when s3 => d<=\"1001\";e<=\"0100\";f<=\"10\"; when s4 => d<=\"0010\";e<=\"0100\";f<=\"11\"; end case;
- 13 -
end process; end keep_arc;
计时模块:-------time module------- library ieee;
use ieee.std_logic_11.all; use ieee.std_logic_unsigned.all; entity time is
port(a,b,k:in std_logic;
c :in std_logic_vector(1 downto 0);
d,e,f,g :out std_logic_vector(3 downto 0); j,h :out std_logic); end time;
architecture time_arc of time is
signal l,m,n,p:std_logic_vector(3 downto 0); begin
process(a,b,k) begin
if(k='0')then l<=\"0101\";m<=\"0010\";n<=\"0000\";p<=\"0010\";----通电后赋初值 else if(a'event and a='1')then
if(b='1')then l<=l;m<=m;n<=n;p<=p;-------有紧急情况时,计时停止 else
if(n=\"0001\" and p=\"0000\")then case c is ----当东西方向倒计时到0时,重
新赋值,并产生使能信号控制交通灯的状态
when \"00\" =>n<=\"0101\";p<=\"0000\";j<='1'; when \"01\"=>n<=\"0101\";p<=\"0010\";j<='1'; when \"11\"=>n<=\"0000\";p<=\"0010\";j<='1'; when \"10\"=>n<=\"0000\";p<=\"0010\";j<='1'; when others =>null; end case;
else j<='0';-----------------------计时未到0时,输出使能信号为0
if(n=\"0000\"and p/=\"0000\")then n<=\"1001\";p<=p-1;---当各位倒计时到0,
而十位没到0时十位减一,个位赋9
else n<=n-1; -------------------------否则,各位减一 end if; end if;
if(l=\"0001\"and m=\"0000\")then-----当南北方向倒计时到0时,重新赋
值,并产生使能信号控制交通灯的状态
case c is when \"00\"=>l<=\"0000\";m<=\"0010\";h<='1'; when \"01\"=>l<=\"0000\";m<=\"0010\";h<='1'; when \"10\"=>l<=\"0101\";m<=\"0000\";h<='1'; when \"11\"=>l<=\"0101\";m<=\"0010\";h<='1'; when others =>null; end case;
else h<='0'; ---------------------计时未到0时,输出使能信号为0
- 14 -
if(l=\"0000\"and m/=\"0000\")then l<=\"1001\";m<=m-1;---当各位倒计时到0,
而十位没到0时十位减一,个位赋9
else l<=l-1; --------------------否则,各位减一 end if; end if; end if; end if; end if; f<=n;g<=p;d<=l;e<=m; end process; end time_arc; 八、实现功能说明 1.基本功能:
(1)南北和东西方向各有一组绿,红,黄灯,各自的持续时间分别为20s,25s,5s; (2)当有特殊情况时,两个方向均为红灯,计时暂停,当特殊情况结束后,控制器恢复原来状态,继续正常工作。
(3)用两组数码管,以倒计时方式显示两个方向允许通行或禁止通行的剩余时间。 2.扩充功能:
当绿大灯亮时,允许左拐。 九、所用器件清单:
(1) EPM7128ls84-15:一块,用于下载程序,实现实验功能; (2) 数码管:四个,用于显示交通灯持续的时间;
(3) 按键:两个,用于产生脉冲,表示有紧急情况发生,再按一次,表示紧急情况消除; (4) 发光二极管:八个,表示交通灯;
(5) 电阻:若干,用于发光二极管、七段数码管和开关的限流。 十、故障及问题分解:
1. 开始时,对实验及模块概念理解不透彻,以致思路不够清楚,处于模糊状态,通过查看
参考资料,对模块及实验对象有了清楚的认识,重新设计各模块,使条理清楚、思路明朗,程序后来的编制也就容易了很多。
2. 计时模块,是显示部件的核心。开始时,在赋值及输出控制信号部分无法正确配合,状
态机各状态之间的转换成为最大的问题(各模块编译成功后,顶层编译也能通过,可就是总体仿真出问题,问题主要是它总是处于一个状态不改变)。分析原因是交通灯的状态由计时模块输出的使能信号确定,因此问题就出在计时模块上。后来发现只需在控制模块加一个输出信号即可。
3. 开关的连接方式很多,对于不同的要求有不同的连接方法。防抖动部件也是控制部分的
重要组成,如果处理不好就难以达到目的。 十一、心得体会:
这次综合实验要求很高,我在思考和设计上花了不少时间,其中收获也是不少。
(1)拿到一个project后,不要急于写程序,首先要搞清楚要干什么,完成什么功能,分几部分完成,每部分完成什么功能,各部分之间的联系。如果采用的是自顶向下的设计思想,那么顶层的设计就很重要,顶层设计好后,下面各部分写起来就比较清楚容易了。一旦出现问题,也好检查错误出在什么地方,哪一部分有问题,就进行相应的改动。
(2)在编程过程中,思路要清楚,明白要实现的功能,然后根据实现的功能一步一步的编写。而且要采用各个击破的办法,先实现下层部分,再整体实现。
(3)编下层时,不用急于仿真,等整体编译成功后,先进行总体仿真,看出现的错误在什么地方,这个地方是由哪个部分控制的,然后再对该部分进行仿真,看有没有问题。
(4)编译成功后,不要急于下载,一定要先仿真,根据仿真波形判断是否达到要求。一般仿真成功后,只要电路连接没问题,下载后就没什么问题了。
- 15 -
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- awee.cn 版权所有 湘ICP备2023022495号-5
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务