基于VHDL的交通灯设计(实训要求)

mac2024-05-31  33

简介

本实验要完成任务就是设计一个简单的交通灯控制器,交通灯显示用实验箱 的交通灯模块和七段码管中的任意两个来显示。系统时钟选择时钟模块的 1KHz 时钟,黄灯闪烁时钟要求为 2Hz,七段码管的时间显示为 1Hz 脉冲,即每 1s 中递减一次,在显示时间小于 3 秒的时候,通车方向的黄灯以 2Hz 的频率闪烁。系统中用 S1 按键进行复位。 该设计基于vhdl程序设计,分别编译分频、计数、数码管、交通灯程序,然后将每个模块连接起来,构成一个系统,完成交通灯的功能实现。其交通灯的燃灭规律为:初始态是两个路口的红灯全亮,之后,东西路口的绿灯亮,南北路口的红灯亮,东西方向通车,延时一段时间后,东西路口绿灯灭,黄灯开始闪烁。闪烁若干次后,东西路口红灯亮,而同时南北路口的绿灯亮,南北方向开始通车,延时一段时间后,南北路口的绿灯灭,黄灯开始闪烁。闪烁若干次后,再切换到东西路口方向,重复上述过程。 结论:由这个设计可以得出,每一个模块都可以单独实现其功能,只要选好输入输出就可以将每个模块连接起来,构建成一个系统,从而综合的完成交通灯的功能。

红绿灯路口模型

方案设计

该系统主要由分为分频模块,计数器模块,交通灯控制模块,数码管控制模块构成。 其中分频模块是将系统输入的基准时钟信号转换成1HZ和2HZ的激励信号,分别驱动计数模块计数和交通灯控制模块。交通灯控制模块根据计数情况,控制交通灯亮灭和蜂鸣器的声音。数码管控制模块根据计数模块将时间以倒计时的形式通过数码管显示出来。

模块设计

时钟模块

模块

从输入端clk输入1khz的时钟信号,经过内部程序设计,将其分为1hz和2hz的信号进行输出,实现了1khz转化到1hz的设计

波形图测试

从波形仿真中可以看出,经过了1k个时钟输入信号clk1hz才得到一次上升沿,也就是相当于,将1khz的信号变为了1hz的信号,同样clk2hz就是clk1hz的一半,在clk500次时得到一次上升沿,将1khz的信号转化为2hz信号。从而达到分频的目的

library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; entity FreDevider is port (clk:in std_logic; clk2hz:out std_logic;--定义时钟输出 clk1hz:out std_logic);--定义时钟输出 end FreDevider; architecture behave of FreDevider is signal clk_count1: std_logic_vector(9 downto 0); begin process(clk) begin if(CLK'EVENT AND CLK='1')THEN--时钟上升沿 IF(clk_count1<1000)then clk_count1<=clk_count1+1;--时钟加计数 else clk_count1<="0000000000"; end if; END IF; end process; clk1hz<=clk_count1(9); CLK2HZ<=CLK_COUNT1(8); end behave;

计数模块

模块

将分频得到的1hz信号输入clk1hz提供时钟激励,外加一个rst复位按键,按下按键进行计数清零。输出sec1和sec10为数码管的个位和十位计数,dir_flag为模式转换的标志输出信号,当其为0时,代表横向通过,为1时代表纵向通过

波形图测试

从波形仿真中可以看出,当1hz信号每次上升沿来的时候个位进行计数加1,当个位加到9后,下一个上升沿来时十位计数加1。当十位完成一次1到0的转换时dir_flag改变一次,也就是发生一次标志位转换(横纵向)

LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_ARITH.ALL; USE IEEE.STD_LOGIC_UNSIGNED.ALL; ENTITY counter IS PORT (CLK1HZ:IN STD_LOGIC; RST:IN STD_LOGIC; SEC1,SEC10:BUFFER INTEGER RANGE 0 TO 9; --缓冲区整数范围0 ~ 9;十进制组成 DIR_FLAG:BUFFER STD_LOGIC); ----------方向 END counter; ARCHITECTURE BEHAVE OF counter IS SIGNAL DIR_FLAG1:STD_LOGIC; BEGIN PROCESS (CLK1HZ,RST) BEGIN IF (RST='0') THEN ----------初始化 SEC1<=0; SEC10<=0; DIR_FLAG<='0'; ELSE IF (CLK1HZ'EVENT AND CLK1HZ='1') THEN ---------上升沿 IF (SEC1=0) THEN SEC1<=9; IF (SEC10=0) THEN -- 方向0 sec10 =1 方向1 sec10=5 SEC10<=1; ELSE SEC10<=SEC10-1; --sec10 !=0 减法运算 END IF; ELSE SEC1<=SEC1-1; --sec1!=0 减法运算 END IF; END IF; END IF; IF (SEC1=0 AND SEC10=0) THEN --计算同时清零,交换方向 DIR_FLAG<=NOT DIR_FLAG; END IF; END PROCESS; END BEHAVE;

数码管控制模块

模块

Sec1与sec10从计数模块获取数码管计数信号作为数码管的输入,dir_flag也是从计数模块中获取标志位转换作为输入,clk为1khz时钟信号,作为数码管驱动扫描信号。Display为7段译码管的输出,其内部程序中定义了“0”~“9”“横向”和“纵向”的显示。Seg_sel为数码管显示的位选输出,其内部定义了数码管的显示端。

波形图测试

由波形图仿真可以看到,当时钟来时dir_flag在低电平时,数码管位选为一个状态,高电平时为一个状态,display为数码管在0~32之间显示,完成了数码管的控制功能

library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; entity dtsm is port(display:out std_logic_vector(6 downto 0); sec1,sec10:in integer range 0 to 9; dir_flag:in std_logic; clk:in std_logic; seg_sel:buffer std_logic_vector(2 downto 0)); end dtsm; architecture behave of dtsm is signal disp_temp: integer range 0 to 15; signal disp_decode: std_logic_vector(6 downto 0); signal direction: integer range 0 to 15; begin process(dir_flag) begin if(dir_flag='0') then direction<=10; else direction<=11; end if; end process; process(seg_sel) begin case(seg_sel+1) is when "000"=>disp_temp<=direction;----0 when "001"=>disp_temp<=direction;---1 when "010"=>disp_temp<=sec10;----2 when "011"=>disp_temp<=sec1;----- 3 数码管位选 when "100"=>disp_temp<=direction;---4 when "101"=>disp_temp<=direction;----5 when "110"=>disp_temp<=sec10;---6 when "111"=>disp_temp<=sec1;----7 end case; end process; process(clk) begin if (clk'event and clk='1') then seg_sel<=seg_sel+1; display<=disp_decode; end if; end process; process (disp_temp) begin case disp_temp is when 0=>disp_decode<="0111111"; when 1=>disp_decode<="0000110"; when 2=>disp_decode<="1011011"; when 3=>disp_decode<="1001111"; when 4=>disp_decode<="1100110"; when 5=>disp_decode<="1101101"; when 6=>disp_decode<="1111101"; when 7=>disp_decode<="0000111"; when 8=>disp_decode<="1111111"; when 9=>disp_decode<="1101111"; when 10=>disp_decode<="1001000";---横向 when 11=>disp_decode<="0010100";-----纵向 when others=>disp_decode<="0000000"; end case; end process; end behave;

红绿灯控制模块

模块

Clk2hz为从分频模块获得的2hz时钟作为输入激励,sec1,sec10为计数模块作为输入控制,dir_flag为状态转换标志位,ret为复位控制键。R1,R2,为两路口的红灯控制,Y1,Y2为两路口黄灯控制,G1,G2为两路口绿灯控制,beep为蜂鸣器控制

波形图测试

从波形中可以看到,当时钟有效时,红黄绿三种灯根据计数的改变而改变,这里只设置了部分数,可以看到当计数在0~3附近时黄灯亮,当dir_flag为低电平时横向绿灯亮,纵向红灯亮,当dir_flag为高电平时纵向绿灯亮横向红灯亮。基本显示了路口红绿灯的功能

library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; entity countroller is port(clk2hz:in std_logic; sec1,sec10:in integer range 0 to 9; dir_flag:in std_logic; rst: in std_logic; R1,R2:out std_logic; --red Y1,Y2:out std_logic; --yellow G1,G2:out std_logic; beep: out std_logic); --green end countroller; architecture behave of countroller is begin process(clk2hz,rst) begin if(rst='0')then --fuwei red 1 other 0 R1<='1'; G1<='0'; R2<='1'; G2<='0'; else ---- if (sec10>0 or sec1>3 ) then if(dir_flag='0') THEN R1<='1'; G1<='0'; R2<='0'; G2<='1'; else R1<='0'; G1<='1'; R2<='1'; G2<='0'; end if; else if(dir_flag='0')then R1<='1'; G1<='0'; R2<='0'; G2<='0'; else R1<='0'; G1<='0'; R2<='1'; G2<='0'; end if; end if; end if; end process; process(clk2hz) begin if (sec10=0 and sec1<5 and dir_flag='0' )then Y1<='0'; Y2<=clk2hz; beep<=clk2hz; elsif(sec10=0 and sec1<5)then Y1<=clk2hz; beep<=clk2hz; Y2<='0'; elsif(sec10=0 and (sec1<6 and sec1>3))then Y1<='1'; Y2<='1'; beep<='1'; else Y1<='0'; Y2<='0'; end if; end process; end behave;

整机电路图设计

各模块连接如上图3.9,加上输入输出,定义引脚仿真调试,成功后,写入试验箱验证功能

调试

总结:"本次实训过程十分艰辛,本想通过网络资源来修改代码,导致自己陷进去,没有自己的思路,使结果不能如愿,写代码还是要全程靠自己的思路写,不要想着取巧,可以说整个实训过程,我是处于非常被动的场面,本想投机取巧的找捷径,结果偷鸡不成,使自己晕头转向。就应该听老师的自己编写程序,这样还可以将程序简单化,自己理解起来也会轻松很多。总之本次实训,让我感受颇深,也让我对vhdl语言有了更加深刻的理解,在以后做项目中,我会铭记这次的教训,老老实实的自己敲程序,少走捷径,脚踏实地的写好自己程序,完成项目。 "

最新回复(0)