⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 light.vhd

📁 A方向和B方向各设红(R)、黄(Y)、绿(G)和左拐(L)4盏灯
💻 VHD
字号:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

--****************路口红绿灯的控制程序*****************--
--a向灯的状态变化为:红(10")-黄(2")-绿(4")-黄(2")-左转(4")-黄(2")
--同时,b向变化为:绿(4")-黄(2")-左转(4")-黄(2")-红(10")-黄(2")
--当阻断某方向时,该方向为红灯,另一方向为绿灯。倒计时10秒后,恢复原来的状态继续执行
entity light is
    Port ( GCLK : in std_logic;
			  set1: in std_logic;
	  		  set2: in std_logic;
	        N : out std_logic_vector(7 downto 0);
           P : out std_logic_vector(3 downto 0)
           );
end light;

architecture Behavioral of light is
SIGNAL divcounter: std_logic_vector(27 downto 0);
SIGNAL divclk:std_logic;
SIGNAL sec_a,sec_b:std_logic_vector(3 downto 0);
SIGNAL state_a,state_b:std_logic_vector(3 downto 0);
SIGNAL temp:std_logic_vector(4 downto 0);
SIGNAL restore_statea,restore_stateb,restore_seca,restore_secb:std_logic_vector(3 downto 0);
SIGNAL divtenmsa,divtenmsb: std_logic_vector(19 downto 0);
SIGNAL blocka,blockb:std_logic;
SIGNAL stopcountera,stopcounterb:std_logic_vector(3 downto 0);
SIGNAL delaya,delayb:std_logic_vector(31 downto 0);

SIGNAL scan:std_logic_vector(8 downto 0);
SIGNAL scan_clk:std_logic_vector(1 downto 0);
SIGNAL SecSega,StaSega,SecSegb,StaSegb : std_logic_vector(7 downto 0);

begin
--将原始信号分频得到1s为周期的时钟信号divclk
DIV_CLOCK:process(GCLK)
begin
   if GCLK='1' and GCLK'event then
        if(divcounter>=X"1312D00") then -- 1312D00为十进制的20 000 000,晶震频率的一半,
		      divcounter<=X"0000000";
		      divclk<=not divclk; 		--故divclk的周期即为1s    				       
        else 
	       divcounter<=divcounter+'1';
        end if;
   end if;
end process;


--产生扫描信号
   SCAN_COUNTER:process(GCLK)
   begin
      if (GCLK'event and GCLK='1') then
	    scan<=scan+1;
      end if;
   end process;
   scan_clk<=scan(8 downto 7);	--恰为3.2微妙

--在扫描信号的作用下,轮流选通各个数码管
OUT_PUT:process(scan_clk)
begin
    case scan_clk is
       when "00"=>
	     N<=SecSega;	--a向的倒计时,显示在第一个数码管
		P<="1000";
       when "01"=>   --a向的灯状态,显示在第二个数码管
	     N<=StaSega;
		P<="0100";       
       when "10"=>	 --b向的灯状态,显示在第三个数码管
	     N<=StaSegb;
		P<="0010";          
       when "11"=>	--b向的倒计时,显示在第四个数码管
	     N<=SecSegb;
		P<="0001";
   when others=>N<="11111111";P<="0000";
  end case;
end process;

--a向秒计数驱动数码管
SECOND_A:process(sec_a)
begin
  case sec_a is
  when "0000" =>SecSega<="10001000";
  when "0001" =>SecSega<="11011011";
  when "0010" =>SecSega<="10100010";
  when "0011" =>SecSega<="10010010";
  when "0100" =>SecSega<="11010001";
  when "0101" =>SecSega<="10010100";
  when "0110" =>SecSega<="10000100";
  when "0111" =>SecSega<="11011010";
  when "1000" =>SecSega<="10000000";
  when "1001" =>SecSega<="10010000";
  when  others =>SecSega<="11111111";
  end case;
end process;

--b向秒计数驱动数码管
SECOND_B:process(sec_b)
begin
  case sec_b is
  when "0000" =>SecSegb<="10001000";
  when "0001" =>SecSegb<="11011011";
  when "0010" =>SecSegb<="10100010";
  when "0011" =>SecSegb<="10010010";
  when "0100" =>SecSegb<="11010001";
  when "0101" =>SecSegb<="10010100";
  when "0110" =>SecSegb<="10000100";
  when "0111" =>SecSegb<="11011010";
  when "1000" =>SecSegb<="10000000";
  when "1001" =>SecSegb<="10010000";
  when  others =>SecSegb<="11111111";
  end case;
end process;

--a向灯状态驱动数码管,state_a记录a向的灯颜色
STATEA:process(state_a) 
begin
  case state_a is
    when "0000" =>StaSega<="11110111";	--状态为"0000"时,红色,管子中间一横亮
    when "0001" =>StaSega<="10111111";	--"0001",表绿色,管子下面一横亮
    when "0010" =>StaSega<="01111111";	--“0010”黄色,右下方的小点亮
    when "0011" =>StaSega<="10101101";	--“0011”左转,L型亮
    when others =>StaSega<="11111111";	--其它状态都灭
  end case;
end process;

--b向灯状态驱动数码管
STATEB:process(state_b) 
begin
  case state_b is
    when "0000" =>StaSegb<="11110111";	 --状态为"0000"时,红色,管子中间一横亮
    when "0001" =>StaSegb<="10111111";	 --"0001",表绿色,管子下面一横亮
    when "0010" =>StaSegb<="01111111";	 --“0010”黄色,右下方的小点亮
    when "0011" =>StaSegb<="10101101";	 --“0011”左转,L型亮
    when others =>StaSegb<="11111111";
  end case;
end process;


--灯状态的转换,divclk是1"为周期的时钟,
--blocka=1,阻断a方向车辆,即a向为红灯,b向为绿灯
--blockb=1,阻断b方向车辆,即b向为红灯,a向为绿灯
--正常情况下,
--a向灯的状态变化为:红(10")-黄(2")-绿(4")-黄(2")-左转(4")-黄(2")
--同时,b向变化为:绿(4")-黄(2")-左转(4")-黄(2")-红(10")-黄(2")
--当阻断某方向时,先保存原状态,阻断完成后,再恢复,继续执行以前的。
SHIFT_STATE:process(divclk, blocka,blockb)
begin
if(divclk'event and rising_edge(divclk)) then	
  if(blocka = '1') then --阻断a向时				
		if(stopcountera = "0000") then  --如果是第一次扫描到阻断信号
				restore_statea <= state_a; --保存a、b方向原状态,秒的计数
				restore_seca <= sec_a;
				restore_stateb <= state_b;
				restore_secb <= sec_b;
												 --初始化a、b方向的两个参数:
				state_a <= "0000";		 --a向灯设为红
				sec_a <= X"9";				 --设置秒数为9,即都从9开始倒计时

				state_b <= "0001";	  --b向灯设为绿
				sec_b <= X"9";
		 else			  					  --如果不是第一次扫描到信号,
			   sec_a <= sec_a - '1';  --a、b秒数减1,即倒计时
			   sec_b <= sec_b - '1';  
		  end if;						 
	 			stopcountera <= stopcountera + '1'; --计数增加

   elsif(blockb = '1') then    --阻断b方向时,基本上同上面一样
     			
				if(stopcounterb = "0000") then
					  restore_statea <= state_a;
					  restore_seca <= sec_a;
					  restore_stateb <= state_b;
					  restore_secb <= sec_b;

					  state_a <= "0001";	  --a向灯设为绿
						sec_a <= X"9";

						state_b <= "0000";  --b向灯设为红
						sec_b <= X"9";
				 else			  
			      sec_a <= sec_a - '1';
			      sec_b <= sec_b - '1';  
		 		 end if;						 
	 			   stopcounterb <= stopcounterb + '1'; 

    else	  --当没有阻断信号时,执行下面的
  					
	      if(stopcountera > "0010") then --如果刚从阻断a状态恢复过来,则先恢复原状态
	              state_a <= restore_statea ;
					  sec_a <= restore_seca  ;
					  state_b <= restore_stateb;
					  sec_b <= restore_secb;
					  stopcountera <= "0000";
	      elsif(stopcounterb > "0010") then--如果刚从阻断b状态恢复过来,也要先恢复原状态
	              state_a <= restore_statea ;
					  sec_a <= restore_seca  ;
					  state_b <= restore_stateb;
					  sec_b <= restore_secb;
					  stopcounterb <= "0000"; 	     
	       else								  --正常执行时,
			       temp <= temp+'1';	  --temp是循环计数的变量,一个循环就是灯从 
				    if(temp >= "10111") then--红(10")-黄(2")-绿(4")-黄(2")-左转(4")-黄(2")
					       temp <= "00000";	 --的变化过程,刚好23秒,10111-00000
					 end if;	      
			     case temp is				--检查temp的值,由temp控制灯的状态变化
			     when "00000" =>		 		--当temp=0000时,将A灯变为绿,B灯变为红,分别设置倒计时时间
					state_a <= "0001";	--a改为绿灯, 等待4"	
					sec_a <= X"3";			--倒计时开始值为3
					
					state_b <= "0000";	 --b红,等待10"
					sec_b <= X"9";
			 when "00100" =>	 			 --4″之后,
			 		state_a <= "0010";	 --a改为黄灯,等待2" ,此时b依然为红
					sec_a <= X"1";
										 					
			      sec_b <= sec_b - '1';  --b向倒计时一次
			 when  "00110" =>	         
			 		state_a <= "0011";	 --2″过后,a改为左转灯,等待4"
					sec_a <= X"3";	 
															
			      sec_b <= sec_b - '1';
			 when "01010" =>	 
			 		state_a <= "0010";	   --a,b 都改为黄灯 2 "
					sec_a <= X"1";

					state_b <= "0010";
					sec_b <= X"1";
			 when  "01100" =>		 
			  		state_a <= "0000";	--a变为红,b变为绿 4"
					sec_a <= X"9";	

					state_b <= "0001";
					sec_b <= X"3";	
			  when  "10000" =>		 					
			      sec_a <= sec_a - '1';	--a为红,b为黄 2" 

					state_b <= "0010";
					sec_b <= X"1";
			  when  "10010" =>		 --a为红,b为左拐 4"
					sec_a <= sec_a - '1';

					state_b <= "0011";
					sec_b <= X"3";	

			   when  "10110" =>		 --a,b都为黄 2"
					state_a <= "0010";
					sec_a <= X"1";

					state_b <= "0010";
					sec_b <= X"1";
			 when others =>			 --temp为中间值的时候,只做倒数
			      sec_a <= sec_a - '1';
			      sec_b <= sec_b - '1';
			 end case;
	  end if;
  end if; 	
end if;  		 	
end process;

--产生阻断a向的信号,blocka=‘1’表示阻断a向,需要消除抖动
CHECKK1:process(set1,blockb,GCLK)
begin
if(blockb = '1') then --先判断是否已经阻断b向,如果已经阻断b向,则不处理阻断a向的请求
else
if(GCLK'event and GCLK = '1') then
 if(blocka = '1')	then	--阻断a成功,保持10秒
    delaya <= delaya +'1';
	 if(delaya >= X"17D78400") then --17D78400为十进制的400M,记录到该值时,刚好为10秒时间
	    blocka <= '0';		 --10秒一过,恢复阻断信号
	  end if;
  else	 --没有任何阻断时,
	  if(set1='1') then	 --按钮没按下,set1='1'
	  		  divtenmsa <= X"00000";
	  elsif(set1 = '0') then -- 如果按钮按下,需要等待10ms,如果还是按下的,则产生阻断信号,这样就实现了按钮的消抖
	  		  divtenmsa <= divtenmsa + '1';	--按钮按下时间的计数,一个GCLK周期加1次 			  
	  end if;	
	  			
	  if(divtenmsa >= X"61A80") then	--如果按钮按下超过10毫秒
	  		if(set1 = '0') then
						blocka <= '1';	 --blocka 设为 1, 表示阻止A向的车辆。
						delaya <= X"00000000";
			elsif(set1 = '1') then
			        blocka <= '0';
			end if;			  
	   divtenmsa <= X"00000"; --计数重新置0
	   end if;
  end if; 
 end if;
end if;
end process;

--产生阻断b向的信号,blockb=‘1’表示阻断b向,操作原理基本同上面
CHECKK2:process(set2,blocka,GCLK)
begin
if(blocka = '1') then 
else
if(GCLK'event and GCLK = '1') then
 if(blockb = '1')	then
    delayb <= delayb +'1';
	 if(delayb >= X"17D78400") then
	    blockb <= '0';
	 end if;
  else
	  if(set2='1') then
	  		  divtenmsb <= X"00000";
	  elsif(set2 = '0') then
	  		  divtenmsb <= divtenmsb + '1';	 			  
	  end if;	
	  			
	  if(divtenmsb >= X"61A80") then
	  		if(set2 = '0') then
						blockb <= '1';	 --blockb = 1 表示阻止B向的车辆。
						delayb <= X"00000000";
			elsif(set2 = '1') then
			        blockb <= '0';
			end if;			  
	  divtenmsb <= X"00000";
	  end if;
  end if; 
 end if; 
end if;
end process;

end Behavioral;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -