课程设计——基于FPGA的交通红绿灯控制系统(源代码)

摘要:

本课程设计旨在设计一个基于FPGA(现场可编程门阵列)的交通红绿灯控制系统。该系统模拟了实际道路交叉口的红绿灯工作场景,通过硬件描述语言(如Verilog或VHDL)编写源代码实现。系统包含三个主要部分:红绿灯显示模块、计时控制模块以及状态切换模块。红绿灯显示模块负责模拟红绿灯的亮灭状态;计时控制模块用于控制每个交通灯状态的持续时间;状态切换模块则根据计时信号和预设的交通规则切换红绿灯状态。通过FPGA的灵活编程能力,该系统能够实现对交通信号灯的精确控制,为智能交通系统提供硬件基础。

关键词 **:**FPGA,Verilog,数码管,led灯

1、 引言

Verilog HDL是现在世界上绝大多数数字IC工程师都在使用的一种硬件描述语言,它已经成为业界内数字电路设计的一种标准硬件描述语言。不同于原理图直接描述电路的结构和功能,它是以文本形式来描述数字电路的结构和功能的[1]。Verilog HDL不但可以采用层次化的逻辑设计,而且还可以用于数字系统的仿真验证(用计算机仿真软件对数字逻辑电路的结构和行为进行分析预测,对HDL行为进行解释,一般的输出形式为波形图),逻辑综合(把硬件描述语言的数字电路逻辑模型转变成电路基本原件以及把这些基本元件进行连接生成电路模型)和时序分析等。Verilog HDL的应用场景有算法级别,寄存器传输级,逻辑级、门级和版图级等各个层级的设计和描述[2]。

FPGA(Field Programmable Gate Array,简称FPGA),翻译成中文就是现场可编程逻辑门阵列, FPGA器件属于专用集成电路中的一种半定制电路,它不像CPLD那样采用两级可编程的"与或"阵列来实现逻辑功能,而是基于查找表的原理来实现组合逻辑函数,能够有效的解决原有的器件门电路数较少的问题。FPGA 的基本结构包括可编程的I/O模块,可编程的逻辑块,数字时钟管理模块,嵌入式只读存储器,可编程连线资源,内部包含专用硬核,底层内嵌多种功能单元[3]。FPGA逻辑功能编程简单,就好像向RAM中写数据一样。由于FPGA具有大量的布线资源,编程更加灵活,集成度更高,适合大规模,高性能的数字系统设计以及投资较低的特点,在数字电路设计领域得到了广泛的应用。

2、 交通灯控制系统设计实现的软硬件

2.1、 硬件

(1)芯片:交通灯控制系统设计使用的 FPGA 芯片型号为 EP2C5T144C8,是属于ALTERA公司 CYCLONE Ⅱ 系列的产品。这款芯片主要的参数为,四千六百零八个逻辑单元LE,两个PLL与13个嵌入式乘法器,RAM存储空间为276480bit,有一百五十八个I/O口,推荐的工作电压是一点一五伏特。

(2)JTAG接口:JIAG(联合测试工作组)接口可以把Quartus软件编译好的Verilog代码(.JIC文件)烧录进FPGA芯片中,因为FPGA是基于随机存储器的一种结构,它的内部没有固化的flash模块,无法存储数据,因此,通过JTAG下载的程序,关掉电源以后就会丢失,所以每次打开电源是都要重新下载才可以。目前,大多数高级部件都支持JTAG协议。

(3)50MHz有源晶振:晶振在数字电路设计中的基本作用是提供一个时序控制的时钟信号。

图1图LED状态指示灯电路

(4)LED状态指示灯电路 :由8个发光二极管L0~L7组成的状态指示灯显示电路,做输出实验 时可同时观察8个输出信号的电平变化。每只发光管的阳极接到3.3V电源,阴极分别串联一个电阻与FPGA芯片的IO脚相连。所接FPGA引脚输出为低电平时,该发光二极管被点亮。

图2 LED数码管电路

(5)LED数码管电路:数码管是一种非常直观而简单的输出显示形式,所以很多电子产品都选择用数码管作 为其显示部件。板载4 位共阳数码管,当位码信号为0 时,对应的数码管即操作;当段码信号为0 时,对应的段码点亮,位码由于电流较大,采用了三极管驱动。

(6)按键低电平有效。

(7)JTAG下载线,USB电源连接线。

图3 硬件实物图

2.2、 软件

(1)Quartus II 13.0:本设计所使用的FPGA开发工具是Altera公司所推出的CPLD/FPGA开发软件Quartus II 13.0。这款软件的功能非常强大,支持原理图、VHDL、Verilog HDL等多种设计输入形式[5]。Quartus软件还具备综合和仿真的功能,可以完成完整的可编程逻辑器件的设计流程。由于其强大的功能和简洁的界面,Quartus II软件现在已经成为FPGA工程师开发项目工程的主流选择之一 。

(2)iverilog:Icarus Verilog(简称iverilog )号称"全球第四大"数字芯片仿真器,也是一个完全开源的仿真器。iverilog以编译器的形式工作, 将以verilog编写的源代码编译为某种目标格式. 如果要进行仿真的话, 它可以生成一个叫做vvp的中间格式.通过"iverilog + gtkwave"的方式,可以很方便地实现商用仿真器的功能。

(3)Notepad++:Notepad++是一款简洁、高效的文本编辑器,支持多种常见的语言,具有很多强大的功能,比如自动保存,编辑只读文件,列编辑,格式编码,查找替换等等,可以为工程师开发工程节省大量的时间和精力。

3、 交通灯控制系统主要功能和设计框图

3.1、 主要功能

两组交通灯的红绿黄三种灯交替点亮,同时数码管显示各个灯的点亮时间。

3.2、 系统总体设计思路

本设计采用自底向上的设计方法[7],有计时块、LED控制块、数码管显示块、时钟分频块四个always块。

3.3、 具体模块分析

  1. 计时块(Timer Block)
    • 功能:负责产生计时信号,用于控制LED和其他模块的操作速度或周期。
    • 实现:使用一个计数器来追踪经过的时钟周期数。当达到预设的阈值时,可以产生一个中断或标志信号。
    • 接口:输入通常是时钟信号和可能的重置信号;输出是计时完成的标志或中断信号。
  2. LED控制块(LED Control Block)
    • 功能:根据当前状态或外部输入控制LED的亮灭模式。
    • 实现:使用状态机(如有限状态机FSM)来管理LED的不同模式或动画。状态机可以根据计时器的信号、用户输入或其他条件进行切换。
    • 接口:输入可能包括来自计时器的信号、用户输入或其他控制信号;输出是控制LED亮灭的信号。
  3. 数码管显示块(Digit Display Block)
    • 功能:显示时间、计数值或其他相关信息在数码管上。
    • 实现:根据输入的数字信号,将其转换为适合数码管显示的编码(如BCD或七段编码)。
    • 接口:输入是数字信号(可能来自计时器或其他数据源);输出是控制数码管段位的信号。
  4. 时钟分频块(Clock Divider Block)
    • 功能:将输入的时钟信号分频,产生不同频率的时钟信号,用于驱动不同速度的模块。
    • 实现:使用计数器来追踪输入的时钟周期数,并在达到某个预设值后产生一个新的时钟周期。
    • 接口:输入是高频的时钟信号;输出是不同频率的分频时钟信号。

4、 代码实现

本设计采用自底向上的设计,是一种简单易实行的设计思路,尤其是对简单的系统控制设计方便快捷。首先确定需要的各个功能,通过不同的always块进行实现,最后通过对整体代码的编译即可实现功能。对于该红绿灯系统只需实现对LED灯与数码管的控制,利用多always块实现使程序易于更改,避免了多模块编程的繁琐。

以下是对给定代码的分段描述和解释:

模块定义

cpp 复制代码
module led(clk,Led,rst,wei,shu);

定义了一个名为led的模块,该模块有五个端口:clk(时钟输入)、Led(LED控制输出)、rst(复位输入)、wei(数码管位选控制输出)和shu(数码管段选控制输出)。

输入输出定义

cpp 复制代码
input wire clk,rst;
reg en=1;
output reg[7:0] Led=8'b01111101;
output reg[3:0] wei=4'b1100;
output reg[7:0] shu;

定义了输入clkrst,以及输出Ledweishu。其中Ledwei有初始值。

内部变量定义

cpp 复制代码
reg [3:0]shuzi;
reg [1:0]cnt_state;
reg [15:0] cnt1;
reg [25:0] cnt=26'b0;
reg [15:0]  tim=24'b0;
reg cc=0,clk1=0;
reg [3:0]data_ew_0,data_ew_1;

定义了内部变量,如shuzi(用于存储数码管显示的数字)、cnt_state(用于状态切换)等。

数码管不同位显示内容

cpp 复制代码
//数码管不同位显示内容
always @*
begin
 data_ew_0=tim%10;
 data_ew_1=tim/10;
 end

根据tim的值,计算数码管两位数的个位和十位,并存储在data_ew_0data_ew_1中。

对50MHz晶振分频

cpp 复制代码
 //对50MHz晶振分频
always@(posedge clk)
begin
 if(cnt == 25000000)
  begin cnt <= 0; clk1 <= ~clk1;	end
  else  begin cnt <= cnt+1'b1;end
end

对输入的clk(假设为50MHz)进行分频,产生新的时钟信号clk1

数码管点亮时间控制

cpp 复制代码
//数码管点亮时间控制
always@(posedge clk)
begin
 if(cnt1 < 250)
  begin cc<=1;cnt1 <= cnt1+1'b1 ;	end
  else if(cnt1<500) begin cnt1 <= cnt1+1'b1;cc<=0;end
  else cnt1 <= 0;
end

控制数码管的点亮时间,通过cc信号来控制。

LED闪烁控制

cpp 复制代码
always @(posedge clk1)
begin 
if(!rst)           begin tim<=0; Led<=8'b111111111; end
     if(tim==3)       begin Led<=8'b01111110;tim<=tim+1;	end
     else if(tim==6)   begin Led<=8'b10111011;tim<=tim+1;	end
	 else if(tim==9)   begin Led<=8'b11011011;tim<=tim+1;	end
	 else if(tim==12)  begin Led<=8'b01111101;tim<=0;	end
     else            tim<=tim+1;
end

根据tim的值和复位信号rst,控制LED的闪烁。

切换数码管点亮的2个状态

cpp 复制代码
//切换数码管点亮的2个状态
always @ (posedge clk)
begin
    if (!rst)
        cnt_state <= 2'b00;
    else  if (cc)
        cnt_state <= 2'b00;
    else
        cnt_state <= 2'b01;
end 

根据复位信号rstcc信号,切换数码管显示的状态(个位或十位)。

数码管显示内容控制

cpp 复制代码
//数码管显示内容控制
always @ (posedge clk)
 begin
    if(!rst) begin
        wei  <= 4'b0000;
        shuzi  <= 4'b0000;
    end 
    else if(en) begin       
        case (cnt_state) 
            2'b00 : begin     
                wei <= 4'b0100;             
                shuzi <= data_ew_1;
            end       
            2'b01 : begin     
                wei <= 4'b1000;              
                shuzi <= data_ew_0;
            end 
				 default : begin     
                wei <= 4'b1100;                     
                shuzi <= 4'b0;end
        endcase
    end
    else  begin
          wei <= 4'b0000;
          shuzi <= 4'b0000;    
    end
end 

根据当前状态cnt_state和复位信号rst,控制数码管显示的位和段。

数码管段选显示

cpp 复制代码
always@(posedge clk)
begin
    if(!rst)
        shu <= 8'hff;
    else begin   //数码管段选显示
        case(shuzi)
            4'd0		:	shu=8'h03;	
			4'd1		:	shu=8'h9f;
			4'd2		:	shu=8'h25;
			4'd3		:	shu=8'h0d;
			4'd4		:	shu=8'h99;
			4'd5		:	shu=8'h49;
			4'd6		:	shu=8'h41;
			4'd7		:	shu=8'h1f;
			4'd8		:	shu=8'h01;
			4'd9		:	shu=8'h19;
            Default  :   shu=8'hff;
        endcase
    end
end
endmodule

根据shuzi的值,控制数码管的段选显示。

代码总结(附源码)

该模块实现了一个基于FPGA的红绿灯和数码管显示系统。其中,数码管用于显示时间(可能是一个倒计时),而LED灯则根据时间进行闪烁。此外,还包括了对时钟的分频和数码管显示的精确控制。

cpp 复制代码
module led(clk,Led,rst,wei,shu);
input wire clk,rst;
reg en=1;
output reg[7:0] Led=8'b01111101;
output reg[3:0] wei=4'b1100;
output reg[7:0] shu;
reg [3:0]shuzi;
reg [1:0]cnt_state;
reg [15:0] cnt1;
reg [25:0] cnt=26'b0;
reg [15:0]  tim=24'b0;
reg cc=0,clk1=0;
reg [3:0]data_ew_0,data_ew_1;
//数码管不同位显示内容
always @*
begin
 data_ew_0=tim%10;
 data_ew_1=tim/10;
 end
 //对50MHz晶振分频
always@(posedge clk)
begin
 if(cnt == 25000000)
  begin cnt <= 0; clk1 <= ~clk1;	end
  else  begin cnt <= cnt+1'b1;end
end
//数码管点亮时间控制
always@(posedge clk)
begin
 if(cnt1 < 250)
  begin cc<=1;cnt1 <= cnt1+1'b1 ;	end
  else if(cnt1<500) begin cnt1 <= cnt1+1'b1;cc<=0;end
  else cnt1 <= 0;
end

always @(posedge clk1)
begin 
if(!rst)           begin tim<=0; Led<=8'b111111111; end
     if(tim==3)       begin Led<=8'b01111110;tim<=tim+1;	end
     else if(tim==6)   begin Led<=8'b10111011;tim<=tim+1;	end
	 else if(tim==9)   begin Led<=8'b11011011;tim<=tim+1;	end
	 else if(tim==12)  begin Led<=8'b01111101;tim<=0;	end
     else            tim<=tim+1;
end
//切换数码管点亮的2个状态
always @ (posedge clk)
begin
    if (!rst)
        cnt_state <= 2'b00;
    else  if (cc)
        cnt_state <= 2'b00;
    else
        cnt_state <= 2'b01;
end 

//数码管显示内容控制
always @ (posedge clk)
 begin
    if(!rst) begin
        wei  <= 4'b0000;
        shuzi  <= 4'b0000;
    end 
    else if(en) begin       
        case (cnt_state) 
            2'b00 : begin     
                wei <= 4'b0100;             
                shuzi <= data_ew_1;
            end       
            2'b01 : begin     
                wei <= 4'b1000;              
                shuzi <= data_ew_0;
            end 
				 default : begin     
                wei <= 4'b1100;                     
                shuzi <= 4'b0;end
        endcase
    end
    else  begin
          wei <= 4'b0000;
          shuzi <= 4'b0000;    
    end
end 

always@(posedge clk)
begin
    if(!rst)
        shu <= 8'hff;
    else begin   //数码管段选显示
        case(shuzi)
            4'd0		:	shu=8'h03;	
			4'd1		:	shu=8'h9f;
			4'd2		:	shu=8'h25;
			4'd3		:	shu=8'h0d;
			4'd4		:	shu=8'h99;
			4'd5		:	shu=8'h49;
			4'd6		:	shu=8'h41;
			4'd7		:	shu=8'h1f;
			4'd8		:	shu=8'h01;
			4'd9		:	shu=8'h19;
            Default  :   shu=8'hff;
        endcase
    end
end
endmodule

5、 仿真

在本次课程设计中,我们利用Iverilog软件对基于FPGA的红绿灯系统进行了功能仿真。通过Iverilog的仿真环境,我们能够模拟红绿灯系统的实际运行情况,验证其逻辑功能的正确性。

在仿真过程中,我们首先编写了红绿灯系统的Verilog源代码,包括红绿灯显示模块、计时控制模块以及状态切换模块的实现。随后,我们将这些代码加载到Iverilog仿真器中,并设置相应的输入信号和仿真时间。

通过运行仿真,我们能够观察到红绿灯系统在不同状态下的运行情况,包括红灯、黄灯、绿灯的亮灭以及它们之间的切换。仿真结果能够直观地展示系统的逻辑功能和时序关系,帮助我们快速定位和解决潜在的问题。

通过本次功能仿真,我们验证了红绿灯系统设计的正确性,为后续的FPGA硬件实现提供了有力的支持。

仿真波形

6、 结论

交通灯控制系统设计采用 Verilog 硬件描述语言,按自底向上的设计方法,将设计的数字系统作为一个整体,通过对四个不同的always块设计 , 分别包括,计时块,时钟分频块,数码管段选块, 数码管位选块,led灯控制块。用iverilog对整体进行仿真得到波形,待到仿真通过后,将程序通过JTAG下载器下载到EP4CE6F17C8芯片中,并在FPGA开发板上验证其功能。经过FPGA开发板的验证实现,本设计完全符合所预期的设计需求。

参考文献

  1. 周景润.基于Quartus的FPGA数字系统设计[M].北京:电子工业出版社,2007:212-306.
  2. Mark Zwolinski.Verilog HDL数字系统设计[M].北京:电子工业出版社,2007.
  3. 黄智伟等.FPGA系统设计与实践[M].北京:电子工业出版社,2005.
  4. 蔡明生.电子设计[M].北京:高等教育出版社,2004.
  5. 周梦然.CPLD/FPGA的开发与应用[M].北京:中国矿业大学出版社,2007.
  6. 刘小俊.基于FPGA技术的IP核设计[J].武汉理工大学学报,2005:43-47.
  7. 冯维川.基于FPGA的多功能空调控制器设计[J].电子技术,2007:67-69.
  8. 阎石.数字电子技术基础:第五版[M]. 北京:高等教育出版社,2006.
  9. 金明.数字统设计与verilog HDL[M].电子工业出版社,2021.
相关推荐
DS小龙哥2 小时前
基于Zynq FPGA的雷龙SD NAND存储芯片性能测试
fpga开发·sd nand·雷龙·spi nand·spi nand flash·工业级tf卡·嵌入式tf卡
西瓜籽@3 小时前
STM32——毕设基于单片机的多功能节能窗控制系统
stm32·单片机·课程设计
上理考研周导师11 小时前
第二章 虚拟仪器及其构成原理
fpga开发
FPGA技术实战13 小时前
《探索Zynq MPSoC》学习笔记(二)
fpga开发·mpsoc
小飞鹰工程师18 小时前
基于Multisim拔河比赛游戏+计分电路(含仿真和报告)
课程设计·数字电路·multisim·模拟电路·数字电子技术
bigbig猩猩1 天前
FPGA(现场可编程门阵列)的时序分析
fpga开发
工业互联网专业1 天前
Python毕业设计选题:基于Hadoop的租房数据分析系统的设计与实现
vue.js·hadoop·python·flask·毕业设计·源码·课程设计
Terasic友晶科技1 天前
第2篇 使用Intel FPGA Monitor Program创建基于ARM处理器的汇编或C语言工程<二>
fpga开发·汇编语言和c语言
码农阿豪1 天前
基于Zynq FPGA对雷龙SD NAND的测试
fpga开发·sd nand·spi nand·spi nand flash·工业级tf卡·嵌入式tf卡