欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

基于FPGA的交通灯

程序员文章站 2022-06-20 12:18:19
...

交通灯是单片机和FPGA都会做的简单项目。本次交通灯做得比较简单,只是模仿一个十字路口的交通灯。

总共有三个模块组成,RTL视图如下:

基于FPGA的交通灯

顶层模块,控制模块,数码管显示模块。代码如下:

顶层模块:

module JTD (CLK,RST_N,LED,SEG_DATA,SEG_EN);

input CLK,RST_N;			//时钟和复位
output [5:0] LED;			//对应的灯分别是X方向红、黄、绿,Y方向红、黄、绿
output [6:0] SEG_DATA;	//数码管段选
output [1:0] SEG_EN;		//数码管位选

wire [3:0] DATA1,DATA0;

segled seg 
(
	.CLK			(CLK),
	.RST_N		(RST_N),
	.DATA_1		(DATA1),
	.DATA_0		(DATA0),
	.SEG_DATA	(SEG_DATA),
	.SEG_EN		(SEG_EN)
);

controler ctr
(
	.CLK			(CLK),
	.RST_N		(RST_N),
	.LED			(LED),
	.data1		(DATA1),
	.data0		(DATA0)
);


endmodule
控制模块:

module controler (CLK,RST_N,LED,data1,data0);

input CLK,RST_N;									//时钟和复位
output reg [5:0] LED;							
output reg [3:0]  data1,data0;				//输出倒计时的十位和个位

parameter TIME_1S 	  = 26'd50_000_000,	//1s晶振所振荡的次数
			 TIME_1S_HALF = 26'd25_000_000;	//0.5s晶振所振荡的次数

reg [25:0] cnt,cnt_n;							//用于计数
reg [3:0]  data1_n,data0_n;					//十位和个位下一个状态的寄存器
reg cnt_1s_half,cnt_1s_half_n;				//0.5s信号

parameter IDLE    = 5'b00001,					//启动与复位后的状态
			 X_PASS  = 5'b00010,					//X方向通行的状态
			 X_FLASH = 5'b00100,					//X方向黄灯闪烁的状态
			 Y_PASS	= 5'b01000,					//Y方向通行的状态
			 Y_FLASH = 5'b10000;					//Y方向黄灯闪烁的状态

reg [4:0] fsm_cs,fsm_ns;						//状态寄存器与下一个状态寄存器

//三段式状态机
always @ (posedge CLK or negedge RST_N)		//给状态寄存器赋值的时序电路
 if (!RST_N)
	fsm_cs <= IDLE;
 else
	fsm_cs <= fsm_ns;

always @ (*)											//给下一个状态赋值的组合电路
case (fsm_cs)
	IDLE		: if ((data0 == 4'd0) && (cnt == TIME_1S) && (data1 == 4'd0))
					fsm_ns = X_PASS;
				  else
					fsm_ns = fsm_cs;
	X_PASS	: if ((data0 == 4'd4) && (cnt == TIME_1S) && (data1 == 4'd0))
					fsm_ns = X_FLASH;
				  else
					fsm_ns = fsm_cs;
   X_FLASH  : if ((data0 == 4'd0) && (cnt ==  TIME_1S) && (data1 == 4'd0))
					fsm_ns = Y_PASS;
				  else
					fsm_ns = fsm_cs;
	Y_PASS	: if ((data0 == 4'd4) && (cnt == TIME_1S) && (data1 == 4'd0))
					fsm_ns = Y_FLASH;
				  else
					fsm_ns = fsm_cs;
   Y_FLASH  : if ((data0 == 4'd0) && (cnt ==  TIME_1S) && (data1 == 4'd0))
					fsm_ns = X_PASS;
				  else
					fsm_ns = fsm_cs;	
	default  : fsm_ns = IDLE;				
 endcase

always @ (*)												//给输出赋值的组合电路
 case (fsm_cs)
	IDLE		: LED = ~6'b100100;
	X_PASS	: LED = ~6'b001100;
   X_FLASH  : LED = ~{1'b0,cnt_1s_half,4'b0100};
	Y_PASS	: LED = ~6'b100001;
   Y_FLASH  : LED = ~{4'b1000,cnt_1s_half,1'b0};
	default  : LED = ~6'b100100;				
 endcase
 
//计数器,产生1HZ的时钟
always @ (posedge CLK or negedge RST_N)
	if (!RST_N)
		cnt <= 26'd0;
	else
		cnt <= cnt_n;

always @ (*)
   if (cnt == TIME_1S)
		cnt_n = 26'd0;
	else 
		cnt_n = cnt + 1'b1;
		
//产生2HZ信号		
always @ (posedge CLK or negedge RST_N)
	if (!RST_N)
		cnt_1s_half <= 1'b0;
	else
		cnt_1s_half <= cnt_1s_half_n;
		
always @ (*)
	if (cnt == TIME_1S_HALF)
		cnt_1s_half_n = cnt_1s_half  + 1'd1; 
	else
		cnt_1s_half_n = cnt_1s_half;
		
//个位计数
always @ (posedge CLK or negedge RST_N)
	if (!RST_N)
		data0 <= 4'd3;
	else
		data0 <= data0_n;

always @ (*)
	if (cnt == TIME_1S)
		begin
			if (data0 == 4'd0)
				begin
					if (data1 == 4'd0)
						data0_n = 4'd0;
					else
						data0_n = 4'd9;
				end
			else
				data0_n = data0 - 4'd1;
		end
	else
		data0_n = data0;
		
//十位计数
always @ (posedge CLK or negedge RST_N)
	if (!RST_N)
		data1 <= 4'b0;
	else
		data1 <= data1_n;
		
always @ (*)
	if ((cnt == TIME_1S) && (data0 == 4'd0))
		begin
			if (data1 == 4'd0)
				data1_n = 4'd2;
			else
				data1_n = data1 - 4'd1;
		end
	else
		data1_n = data1;
		
endmodule
数码管显示代码:

module segled (CLK,RST_N,DATA_1,DATA_0,SEG_DATA,SEG_EN);

input  CLK,RST_N;
input  [3:0] DATA_1,DATA_0;
output reg [6:0] SEG_DATA;
output [1:0] SEG_EN;

parameter SET_TIME_1MS = 16'd50_000;

reg [15:0] cnt,cnt_n;
reg [1:0] SEG_EN_N; 
reg cnt_seg,cnt_seg_n;

always @ (posedge CLK or negedge RST_N)
 begin
	if (!RST_N)
		cnt <= 16'd0;
	else
		cnt <= cnt_n;
 end
 
always @ (*)
begin
	if (cnt == SET_TIME_1MS)
		cnt_n = 16'd0;
	else
		cnt_n = cnt + 1'b1;
end


always @ (posedge CLK or negedge RST_N)
 if (!RST_N)
	cnt_seg <= 1'b0;
else
	cnt_seg <= cnt_seg_n;
	
	
always @ (*)
if (cnt == SET_TIME_1MS)
	cnt_seg_n = ~cnt_seg;
else
	cnt_seg_n = cnt_seg;
	
assign SEG_EN = cnt_seg ? 2'b10 : 2'b01;

wire [3:0] led = cnt_seg ? DATA_1 : DATA_0;

always @ (*)
begin
  case(led )
		0  :  SEG_DATA = 7'b0111111;   		//显示数字 "0"
		1  :  SEG_DATA = 7'b0000110;  		//显示数字 "1"
		2  :  SEG_DATA = 7'b1011011;   		//显示数字 "2"
		3  :  SEG_DATA = 7'b1001111;   		//显示数字 "3"
		4  :  SEG_DATA = 7'b1100110;  		//显示数字 "4"
		5  :  SEG_DATA = 7'b1101101;   		//显示数字 "5"
		6  :  SEG_DATA = 7'b1111101;   		//显示数字 "6"
		7  :  SEG_DATA = 7'b0000111;   		//显示数字 "7"
		8  :  SEG_DATA = 7'b1111111;   		//显示数字 "8"
		9  :  SEG_DATA = 7'b1101111;  		//显示数字 "9"
		default : SEG_DATA = 7'b0000000; 	//显示数字 "0"
  endcase
end

endmodule