FPGA交通信号灯设计报告(VHDL语言)

本文详细描述了一项使用FPGA设计的交通灯控制系统,涉及VHDL编程、多进程控制(计数器、红绿灯显示和数码管动态显示)、以及在quartusii中的仿真过程。作者分享了遇到的问题、解决方案和改进点,展示了学习和实践中的收获。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

FPGA的大作业我选择了交通灯控制系统的设计,此课程只有2个学分,因此只需要在相应软件仿真出结果即可。以下是我的设计报告,当时写的匆忙,没有对代码进行优化改进,但仿真结果是正确的,可以给大家提供一下思路。

一、任务分析

请添加图片描述

分析设计要求可以看出,本系统设计数码管动态显示、译码器、计数器分频方面的知识。

1.输入和输出

  1. 输入

    clk:时钟输入(50MHz)。

    special:特殊情况发生输入。

  2. 输出

    l1、l2:数码管位选。

    display_1、display_2:数码管段选。

    out_1、out_2:红绿灯选择。

2.多进程

  1. reg进程:分频计数

    • 红绿灯的闪烁和数码管显示数字的变化都需要计时,计时单位为s(秒)时,设计最简单。因此,我将50MHz频率的clk驱动分频,这部分运用了计数器知识。

    • 从题目中看出,红绿灯50s为一个循环,我使用信号counter来记录时间,时钟每过1秒钟,counter就加1,counter的值不能超过50。

  2. com进程:红绿灯显示

    • 通过counter的值就可以判断出东西方和南北方的灯为什么颜色。我使用自定义枚举类型来表示红绿灯的三种状态。

    • 在判断红绿灯状态的同时,还应该计算出数码管应该显示的数字为多少。

  3. smg进程:数码管显示

    • 将com进程中计算出的数码管数字在数码管上显示出来。计算数码管十位上的显示数字时用10取模,计算数码管个位上的显示数字时用10取余。
    • 由于数码管位选仅有两个,我使用一个变量的0和1分别表示数码管的十位显示和个位显示。
    • 数码管的段选运用了译码器相关知识。

3.特殊情况

  1. 当bit类型信号special为’1’时,进入特殊情况处理。

  2. 在com进程中,只有当special为’0’时,counter才会加1。目的是在特殊情况时,数码管的数字不会发生变化。

  3. 我额外定义了一个bit类型信号change,时钟每过一秒钟,它就会取反。使用它的目的是在特殊情况时,实现数码管闪烁。

4.注意

需要格外注意的是,reg、com、smg三个进程的敏感信号。

reg:process(clk,special)

com:process(counter,special)

红绿灯显示在每隔1秒钟判断或special特殊情况到来时判断即可

reg:process(clk,change,special)

数码管为动态扫描,只有速度够快,才能使人眼无法察觉数码管的交替显示,因此需要clk时钟信号作为敏感信号。

二、quartus ii 仿真

1.VHDL语言描述

library ieee;
use ieee.std_logic_1164.all;
entity fisrt is
--两组数码管(段选+位选),两组灯
	port(clk:in std_logic;
			special:in bit;
       		--数码管段选
			l1,l2:out std_logic_vector(1 downto 0);
       		--数码管位选
			display_1,display_2:out std_logic_vector(6 downto 0);
       		--红绿灯
			out_1,out_2:out std_logic_vector(2 downto 0));
end fisrt;
architecture behav of fisrt is
	type FSM is (s0,s1,s2);
	signal LED_1,LED_2:FSM;--自定义枚举类型
	signal counter:integer range 0 to 49;--共50s
	signal smg_1,smg_2:integer range 0 to 24;--数码管显示数字
	signal change:bit;--每一秒钟用于变化的量
begin

--进程reg用于分频
	reg:process(counter,special)
		variable clk1:integer range 0 to 9999;--50MHz分频为1Hz
		variable clk2:integer range 0 to 4999;
	begin
		if clk'event and clk='1' then
			if clk1=9999 then
				clk1:=0;
				if clk2=4999 then
					clk2:=0;
					if special='0' then
						change<=not change;
						if counter=49 then
							counter<=0;
						else counter<=counter+1;
						end if;
					end if;
				else clk2:=clk2+1;
				end if;
			else clk1:=clk1+1;
			end if;
	  end if;
	end process reg;


--进程com用于红绿灯显示
	com:process(clk,counter,special)
	begin
		if special='1' then
			out_1<="100";
			out_2<="100";
		else
			if counter<20 then
				LED_1<=s0;smg_1<=20-counter;
				LED_2<=s0;smg_2<=25-counter;
			elsif counter<25 then
				LED_1<=s1;smg_1<=25-counter;
				LED_2<=s0;smg_2<=25-counter;
			elsif counter<45 then
				LED_1<=s2;smg_1<=50-counter;
				LED_2<=s1;smg_2<=45-counter;
			else LED_1<=s2;smg_1<=50-counter;
				   LED_2<=s2;smg_2<=50-counter;
			end if;
			
			case LED_1 is
				when s0=>out_1<="010";--绿灯亮
				when s1=>out_1<="001";--黄灯亮
				when s2=>out_1<="100";--红灯亮
			end case;
			case LED_2 is
				when s0=>out_2<="100";--红灯亮
				when s1=>out_2<="010";--绿灯亮
				when s2=>out_2<="001";--黄灯亮
			end case;
		end if;
	end process com;
	
--进程smg用于数码管显示
	smg:process(clk,change,special)
	variable a,b:bit;
	variable c1,c2:integer range 0 to 10;
	begin
    if clk'event and clk='1' then
		a:=not a;
		b:=not b;
		case a is
			when '0'=> l1<="01";c1:=smg_1 rem 10;--取个位数
			when '1'=> l1<="10";c1:=smg_1 mod 10;--取十位数
		end case;
		case b is
			when '0'=> l2<="01";c2:=smg_2 rem 10;
			when '1'=> l2<="10";c2:=smg_2 mod 10;
		end case;
		
		if special='1' and change='1' then --特殊情况时,数码管1s闪烁一次
			c1:=10;c2:=10;
		end if;
		
		case c1 is
			when 0 =>display_1<="0111111";
			when 1 =>display_1<="0000110";
			when 2 =>display_1<="1011011";
			when 3 =>display_1<="1001111";
			when 4 =>display_1<="1100110";
			when 5 =>display_1<="1101101";
			when 6 =>display_1<="1111101";
			when 7 =>display_1<="0000111";
			when 8 =>display_1<="1111111";
			when 9 =>display_1<="1100011";
			when others=>display_1<="0000000";
		end case;
		case c2 is
			when 0 =>display_2<="0111111";
			when 1 =>display_2<="0000110";
			when 2 =>display_2<="1011011";
			when 3 =>display_2<="1001111";
			when 4 =>display_2<="1100110";
			when 5 =>display_2<="1101101";
			when 6 =>display_2<="1111101";
			when 7 =>display_2<="0000111";
			when 8 =>display_2<="1111111";
			when 9 =>display_2<="1100011";
			when others=>display_2<="0000000";
		end case;
    end if;
	end process smg;
end behav;

2.仿真结果

  • RTL Viewer

请添加图片描述

  • 时序仿真

为了方便仿真,我将clk1和clk2去除,将clk设置为1Hz频率的时钟信号,下图为修改后代码。这样仿真的缺点就是,数码管无法显示出完整数字,在每过一秒钟,交替显示十位数码管和个位数码管。
在这里插入图片描述
仿真结果如下:

请添加图片描述

三、总结

1.收获

设计交通信号灯控制系统,我熟悉了计数器、译码器、动态数码管显示的知识,加深对它们的工作原理的理解,更加熟练的使用case、if等语句。同时,也进一步熟悉EDA软件——quartusii,提高代码构思能力。

2.问题与解决

  1. 编译过程中出现很多语法错误,例如process进程忘记加begin,定义的整型类型忘记加range,变量赋值语句的符号为“ := ”,if语句没有加then,忘记写“end if”…

    这些语法错误在编译后的error中查找并改正。

  2. 构思VHDL代码结构时,最大的困难就是数码管显示数字和特殊情况处理。

    • 我将数码管显示数字的计算和判断红绿灯代码放到了一起,利用counter信号50s一循环,红绿灯50s一循环,在根据红、绿、黄灯的持续时间,就可以将数码管数字计算出来。

    • 特殊情况是最难处理的地方。它不仅要求在此时红灯亮,还需要让数码管闪烁。我将数码管设置为1s闪烁,具体实现方法是,在com进程让change信号每过1s取反,在smg进程中,当special=‘1’ 并且change='1’时,数码管不显示数字。

3.改进与优化

  1. 数码管显示数字部分可以看出,这个程序在显示数字小于10时,两位数码管显示为"0X",也就是说十位上的数码管有数据显示,这是不符合现实的,因此,可以更改为以下代码。

    --smg进程部分
    case a is
    	 when '0'=> l1<="01";c1:=smg_1 rem 10;--取个位数
    	 when '1'=> l1<="10";c1:=smg_1 mod 10;--取十位数
    			if c1=0 then 
            		c1:=10;--此时数码管不显示
    			end if;
    end case;
    case b is
    	 when '0'=> l2<="01";c2:=smg_2 rem 10;
    	 when '1'=> l2<="10";c2:=smg_2 mod 10;
    			if c2=0 then 
            		c2:=10;--此时数码管不显示
    			end if;
    end case;
    
    
  2. 通过理解题目内容可以看出,东西方和南北方的数码管显示和灯颜色的选择是相似的,可以设计子程序,通过函数调用或过程调用优化代码。但因本人能力有限,没有写出具体实现方法。

本实验设计一个十字路口的交通灯控制器,分为东西和南北两个部分。每个部分有五盏灯,分别为左转灯、直行灯、右转灯、人行道灯及黄灯,另外还有一个倒计时器。左转灯、直行灯、右转灯、人行道灯亮表示允许通行,灯灭表示禁止通行;黄灯亮表示即将有信号灯的状态发生改变;倒计时显示了到下一状态的时间。 2.状态表(0表示灯灭,1表示灯亮) 时间度量 东西方向  南北方向 东西方向 南北方向 t/s ← ↑ → 行人 黄 ← ↑ → 行人 黄 倒计时/s 倒计时/s 0~13 0 1 1 0 0 0 0 0 0 0 13 45 13~15 0 1 1 0 1 0 0 0 0 0 2   15~28 0 1 0 1 0 0 0 0 0 0 13   28~30 0 1 0 1 1 0 0 0 0 0 2   30~43 1 0 0 0 0 0 0 0 0 0 13   43~45 1 0 0 0 1 0 0 0 0 0 2   45~58 0 0 0 0 0 0 1 1 0 0 45 13 58~60 0 0 0 0 0 0 1 1 0 1   2 60~73 0 0 0 0 0 0 1 0 1 0   13 73~75 0 0 0 0 0 0 1 0 1 1   2 75~88 0 0 0 0 0 1 0 0 0 0   13 88~90 0 0 0 0 0 1 0 0 0 1   2 3.状态图(低电平表示灯灭,高电平表示灯亮) 4.顶层设计图 如图所示,交通灯控制器主要分为三个模块,交通灯状态控制,交通灯显示和倒计时。交通灯状态控制模块:接受频率为1Hz的时钟信号,根据该信号进行处理,对交通灯显示和倒计时模块给出相应的状态编号(12个状态)。交通灯显示模块:通过相应的状态设置两组交通灯的亮灭。倒计时模块:通过相应的状态确定倒计时的基数及显示。
使用Quartus II设计交通信号灯系统,可以通过硬件描述语言(如VHDL或Verilog)来实现。以下是一个简单的设计思路和步骤: ### 设计思路 1. **状态定义**:定义交通信号灯的不同状态,如红灯、绿灯、黄灯。 2. **持续时间**:为每个状态设置持续时间。 3. **一键暂停键**:实现一个按键,用于暂停和恢复信号灯的状态。 ### 设计步骤 1. **定义状态机**:使用状态机来管理信号灯的状态切换。 2. **计数器**:使用计数器来控制每个状态的持续时间。 3. **按键检测**:实现按键检测逻辑,用于暂停和恢复信号灯。 ### 示例代码(Verilog) ```verilog module traffic_light( input clk, input reset, input pause, output reg red, output reg yellow, output reg green ); // 状态定义 typedef enum reg [1:0] { RED = 2'b00, GREEN = 2'b01, YELLOW = 2'b10 } state_t; state_t current_state, next_state; // 计数器参数 parameter RED_TIME = 32'd10; parameter GREEN_TIME = 32'd10; parameter YELLOW_TIME = 32'd3; reg [31:0] counter; // 状态切换逻辑 always @(posedge clk or posedge reset) begin if (reset) begin current_state <= RED; counter <= 32'd0; end else if (!pause) begin current_state <= next_state; end end // 状态转换逻辑 always @(*) begin case (current_state) RED: begin if (counter < RED_TIME) next_state = RED; else next_state = GREEN; end GREEN: begin if (counter < GREEN_TIME) next_state = GREEN; else next_state = YELLOW; end YELLOW: begin if (counter < YELLOW_TIME) next_state = YELLOW; else next_state = RED; end default: next_state = RED; endcase end // 计数器逻辑 always @(posedge clk or posedge reset) begin if (reset) counter <= 32'd0; else if (!pause) begin if (counter < (current_state == RED ? RED_TIME : current_state == GREEN ? GREEN_TIME : YELLOW_TIME)) counter <= counter + 32'd1; else counter <= 32'd0; end end // 输出逻辑 always @(posedge clk or posedge reset) begin if (reset) begin red <= 1'b1; yellow <= 1'b0; green <= 1'b0; end else if (!pause) begin case (current_state) RED: begin red <= 1'b1; yellow <= 1'b0; green <= 1'b0; end GREEN: begin red <= 1'b0; yellow <= 1'b0; green <= 1'b1; end YELLOW: begin red <= 1'b0; yellow <= 1'b1; green <= 1'b0; end endcase end end endmodule ``` ### 说明 1. **状态机**:使用枚举类型定义状态机状态。 2. **计数器**:根据当前状态设置计数器上限。 3. **按键检测**:通过`pause`信号控制状态机的暂停和恢复。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值