Verilog 交通灯控制器

简介:
设计一个交通灯控制器,在数码管上以红、黄、绿三种颜色显示当前状态的剩余时间。持续时间分别为:红灯30s,黄灯5s,绿灯30s。初始为红灯,依次变为绿灯、黄灯、红灯循环显示。输入时钟为1k Hz。
系统设计:
分析需求,可将交通控制器系统划分为generate_1s、controller、counter、splitter和decoder5_7共五个模块实现。
交通灯控制器顶层框图如下:
Verilog 交通灯控制器_第1张图片
controller状态转移图如下:
Verilog 交通灯控制器_第2张图片
Verilog完整代码实现如下:

/*-------------------------------------------------
Filename: traffic_light_controller.v
Function: 交通灯控制器顶层模块(用于综合成实际电路)
Author: Zhang Kaizhou
Date: 2019-11-17 14:28:50
-------------------------------------------------*/
`include "generate_1s.v"
`include "counter.v"
`include "controller.v"
`include "splitter.v"
`include "decoder5_7.v"
module traffic_light_controller(sys_clk, reset, data_high, data_low, state);
	//输入输出端口定义
	input sys_clk, reset;
	output [1 : 0] state;
	output [6 : 0] data_high, data_low;
	
	//内部寄存器及连线定义
	wire count_clk;
	wire [6 : 0] data;
	wire [3 : 0] data_shi, data_ge;
	
	//逻辑实现
	generate_1s		generate_1s_m0(.sys_clk(sys_clk), .reset(reset), .y(count_clk));
	counter			counter_m0(.count_clk(count_clk), .reset(reset), .data(data));
	controller		controller_m0(.clk(count_clk), .reset(reset), .din(data), .state(state));
	splitter		splitter_m0(.data(data), .data_shi(data_shi), .data_ge(data_ge));
	decoder5_7		decoder5_7_m0(.reset(reset), .data_shi(data_shi), .data_ge(data_ge), .data_high(data_high), .data_low(data_low));
endmodule
/*--------------------------------------
Filename: generate_1s.v
Function: 将1kHz系统时钟分频产生1Hz时钟
Author: Zhang Kaizhou
Date: 2019-11-17 14:28:56
--------------------------------------*/
module generate_1s(sys_clk, reset, y);
	//定义输入输出端口
	input sys_clk, reset;
	output y;
	
	//内部寄存器定义
	reg y;
	reg [9 : 0] cnt;
	
	//逻辑实现
	always@(posedge sys_clk or negedge reset)
	begin
		if(!reset)
		begin
			y <= 1'b0;
			cnt <= 10'd0;
		end
		else
		begin
			if(cnt == 10'd999)
			begin
			y <= 1'b1;
			cnt <= 10'd0;
			end
			else
			begin
				y <= 1'b0;
				cnt <= cnt + 1;
			end
		end
	end
endmodule
/*---------------------------------------------
Filename: counter.v
Function: 7位循环减计数器(用于倒计时和状态转移)
Author: Zhang Kaizhou
Date: 2019-11-17 14:29:01
---------------------------------------------*/
module counter(count_clk, reset, data);
	//输入输出端口定义
	input count_clk, reset;
	output [6 : 0] data; //64~35, 34~5, 4~0循环减计数
	
	//内部寄存器定义
	reg [6 : 0] data;
	
	//逻辑实现
	always@(posedge count_clk or negedge reset)
	begin
		if(!reset) data <= 7'd64; //异步复位
		else if(data == 7'd0) data <= 7'd64;
		else data <= data - 7'd1;
	end
endmodule	
/*-------------------------------------------------
Filename: controller.v
Function: 整个电路的控制模块(用FSM实现)
Author: Zhang Kaizhou
Date: 2019-11-17 14:29:06
-------------------------------------------------*/
module controller(clk, reset, din, state);
	//定义输入输出端口
	input clk, reset;
	input [6 : 0] din;
	output [1 : 0] state;
	
	//内部寄存器定义
	reg [1 : 0] state, current_state, next_state;
	
	//状态编码
	parameter red = 2'b00, green = 2'b01, yellow = 2'b10;
	
	//时序逻辑实现状态转移
	always@(posedge clk or negedge reset)
	begin
		if(!reset) current_state <= red;
		else current_state <= next_state;
	end
	
	//组合逻辑实现转移条件判断
	always@(current_state or din)
	begin
		case(current_state)
			red: next_state = (din == 7'd35) ? green : red;
			green: next_state = (din == 7'd5) ? yellow : green;
			yellow: next_state = (din == 7'd0) ? red : yellow;
		endcase
	end
	
	//组合逻辑实现输出
	always@(current_state)
	begin
		case(current_state)
			red: state = 2'b00;
			green: state = 2'b01;
			yellow: state = 2'b10;
		endcase
	end
endmodule
/*------------------------------------------------------------
Filename: splitter.v
Function: 将输入的7位二进制数转换成2个4位的BCD码(分离十位和个位)
Author: Zhang Kaizhou
Date: 2019-11-17 14:29:10
------------------------------------------------------------*/
module splitter(data, data_shi, data_ge);
	//输入输出端口定义
	input [6 : 0] data;
	output [3 : 0] data_shi;
	output [3 : 0] data_ge;
	
	//内部寄存器定义
	reg [3 : 0] data_shi, data_ge;
	reg [6 : 0] data_display;
	
	//显示数据转换
	always@(data)
	begin
		if(data >= 7'd35) data_display = data - 7'd35;
		else if(data >= 7'd5) data_display = data - 7'd5;
		else data_display = data;
	end
	
	//用左移加3法将7位二进制数转换为两个4位的BCD码
	integer i;
	always@(data)
	begin
		data_shi = 4'd0;
		data_ge = 4'd0;
		
		for(i = 6; i >= 0; i = i - 1)
		begin
			if(data_ge >= 4'd5) data_ge = data_ge + 4'd3;
			if(data_shi >= 4'd5) data_shi = data_shi + 4'd3;
		
			data_shi = data_shi << 1;
			data_shi[0] = data_ge[3];
			data_ge = data_ge << 1;
			data_ge[0] = data_display[i];
		end
	end
endmodule
/*------------------------------------------------
Filename: decoder5_7.v
Function: 将4位BCD码数据转换为7段数码管的显示数据
Author: Zhang Kaizhou
Date: 2019-11-17 14:29:16
------------------------------------------------*/
module decoder5_7(reset, data_shi, data_ge, data_high, data_low);
	//输入输出端口定义
	input reset;
	input [3 : 0] data_shi, data_ge;
	output [6 : 0] data_high, data_low;
	
	//内部寄存器定义
	reg [6 : 0] data_high, data_low;
	
	//译码个位数
	always@(reset or data_ge)
	begin
		if(!reset)
		begin
			data_high <= 7'b0000110; //7'h06
			data_low <= 7'b0000001; //7'h01
		end
		else
		begin
			case(data_ge)
				4'd0: data_low <= 7'b0000001; //7'h01
				4'd1: data_low <= 7'b1001111; //7'h4f
				4'd2: data_low <= 7'b0010010; //7'h12
				4'd3: data_low <= 7'b0000110; //7'h06
				4'd4: data_low <= 7'b1001100; //7'h4c
				4'd5: data_low <= 7'b0101100; //7'h2c
				4'd6: data_low <= 7'b0100000; //7'h20
				4'd7: data_low <= 7'b0001111; //7'h0f
				4'd8: data_low <= 7'b0000000; //7'h00
				4'd9: data_low <= 7'b0000100; //7'h04
				default: data_low <= 7'b0110000; //7'h48
			endcase
		end
	end
	
	//译码十位数
	always@(reset or data_shi)
	begin
		if(!reset)
		begin
			data_high <= 7'b0000110; //7'h06
			data_low <= 7'b0000001; //7'h01
		end
		else
		begin
			case(data_shi)
				4'd0: data_high <= 7'b0000001; //7'h01
				4'd1: data_high <= 7'b1001111; //7'h4f
				4'd2: data_high <= 7'b0010010; //7'h12
				4'd3: data_high <= 7'b0000110; //7'h06
				default: data_high <= 7'b0110000; //7'h48
			endcase
		end
	end
endmodule
/*---------------------------------------------------------
Filename: top_t.v
Function: 交通灯控制器整个系统的顶层测试文件(用于仿真测试)
Author: Zhang Kaizhou
Date: 2019-11-17 14:29:23
---------------------------------------------------------*/
`timescale 1ms/100us
`define sys_clk_half_period 0.5 //系统时钟频率为1kHz,其半周期为0.5ms
`include "generate_1s.v"
`include "counter.v"
`include "controller.v"
`include "splitter.v"
`include "decoder5_7.v"
module top_t(data_high, data_low, state);
	//输入输出端口定义
	output [1 : 0] state;
	output [6 : 0] data_high, data_low;
	
	//内部寄存器及连线定义
	reg sys_clk, reset;
	wire count_clk;
	wire [6 : 0] data;
	wire [3 : 0] data_shi, data_ge;
	
	//产生测试信号
	initial
	begin
		sys_clk = 0;
		#5 reset = 1;
		#5 reset = 0;
		#9.5 reset = 1;
		#120000 $stop; //仿真120s停止
	end
	
	//产生1kHz的系统时钟sys_clk
	always #`sys_clk_half_period sys_clk = ~sys_clk;
	
	//结构描述
	generate_1s		generate_1s_m0(.sys_clk(sys_clk), .reset(reset), .y(count_clk));
	counter			counter_m0(.count_clk(count_clk), .reset(reset), .data(data));
	controller		controller_m0(.clk(count_clk), .reset(reset), .din(data), .state(state));
	splitter		splitter_m0(.data(data), .data_shi(data_shi), .data_ge(data_ge));
	decoder5_7		decoder5_7_m0(.reset(reset), .data_shi(data_shi), .data_ge(data_ge), .data_high(data_high), .data_low(data_low));
endmodule

ModelSim10.4仿真结果:
Verilog 交通灯控制器_第3张图片
总结:
由上面的仿真结果可知,本次设计的交通灯控制电路实现了,在输入1kHz时钟的驱动下,在数码管上以红、黄、绿(状态编码分别为2’d0、2’d1、2’d2)三种颜色显示当前状态的剩余时间。持续时间分别为:红灯30s,黄灯5s,绿灯30s。初始为红灯,依次变为绿灯、黄灯、红灯循环显示。相应的数码管驱动数据也正确。完成了设计预期。

你可能感兴趣的:(FPGA相关)