verilog代码实现模拟交通灯

verilog代码实现模拟交通灯

题目要求如下

模拟交通灯
输入信号:时钟信号clk
输出信号:东西向红黄绿灯信号r1、y1、g1以及南北向红黄绿灯信号r2、y2、g2
设计要求:
1、输出高电平表示相应灯点亮,低电平表示相应灯熄灭。
2、初始时东西向绿灯,g1输出高电平,南北向红灯,r2输出高电平。
3、12个时钟脉冲(可统一使用时钟脉冲的上升沿或者下降沿,下同)后,原绿灯方向变为黄灯,再3个时钟脉冲后,黄灯方向变红灯,同时原红灯方向变绿灯;随后又是12个时钟脉冲后,当前绿灯方向又变为黄灯,再过3个时钟脉冲后,黄灯方向变红灯,同时当前红灯方向又变为绿灯,如此循环往复。
4、绿灯变为黄灯前,绿灯必须先闪烁数次以作为提示,即第8个时钟脉冲到来后绿灯暂时熄灭,第9个时钟脉冲到来后绿灯重新点亮,第10个时钟脉冲到来后绿灯又熄灭,第11个时钟脉冲到来后绿灯又点亮,直到第12个时钟脉冲到来后绿灯才变为黄灯,此功能必须实现。
5、设法消除输出信号中的干扰脉冲(“毛刺”),此功能必须实现。

分析

在这个模拟交通灯系统中,我们需要根据输入信号:时钟信号clk输出东西向红黄绿灯信号r1、y1、g1以及南北向红黄绿灯信号r2、y2、g2。整个系统要求输出高电平表示相应灯点亮,低电平表示相应灯熄灭,并且初始状态下东西向道路为绿色,南北向道路为红色。此外,在每一个方向上车辆可以行驶的时间是有限制的,并且在不同时期会出现所谓“闪烁”等特殊情况。

TLCounter模块设计

对于计数器模块,我们需要实现以下的功能需求:①能够循环计数0~27,并根据计数值更新交通信号灯状态。②在每个时间单位内,交通信号灯的状态都需要被同步更新。③交通信号灯的控制信号需要被输出到特定的IO口。
TLCounter模块由一个5位二进制寄存器组成,用于循环计数0~27。其中第一位最低位作为使能端口(enable),其余四位可表示16种状态,在此我们仅使用其中12种状态作为交通灯各个阶段。每当计数器的值变化时,就会触发TLDecoder模块更新输出状态。在该设计中,我们使用了简单的异或逻辑实现二进制寄存器的自加1操作。
具体实现代码如下:

module TLCounter(clk,cnt);//0~27 循环计数
	input clk;
	output[4:0] cnt;
	reg[4:0] cnt=5'b00001;
	assign clr=~(cnt[0]&cnt[1]&(cnt[2])&cnt[3]&cnt[4]);
	always @(posedge clk)
	begin
		begin
		cnt[0] <= (~cnt[0]);
		cnt[1] <= (cnt[1] ^ cnt[0]);
		cnt[2] <= (cnt[2] ^ (cnt[0] & cnt[1]));
		cnt[3] <= (cnt[3] ^ (cnt[0] & cnt[1] & cnt[2]));
		cnt[4] <= (cnt[4] ^ (cnt[0] & cnt[1] & cnt[2] & cnt[3]));
		end
	end
endmodule

在上面的代码中,我们首先定义了一个输入时钟信号(clk)、使能信号(enable)和一个用于输出计数器数值的信号(cnt)。然后,我们使用reg关键字声明了一个名为cnt的寄存器,并将其初始化为5’b00001。
接下来是关键的部分:在顺时针上升沿时,如果使能信号enable为高电平,则寄存器cnt的值会自动加1。具体实现方法是使用异或逻辑运算符(^)对各个二进制位进行比较和修改。通过这样的方式,我们就成功地实现了一个简单的计数器模块。

TLDecoder模块设计

TLDecoder模块是由一个组合电路构成,它将计数器产生的信号解码成相应的交通灯控制信号。具体实现采用了基于嵌套语句和位运算符构建的多层分支结构来判断当前处于哪种状态,并生成相应控制信号。
具体实现代码如下:

module TLDecoder(cnt,light,clk);
	input clk;
	input[4:0] cnt;
	output[5:0] light;
	reg[5:0] light=6'b001100;
	always @(posedge clk)//所有的输出信号都将在时钟的上升沿同步更新,从而消除可能的毛刺
	begin		 light[5]<=((cnt[4]&(~cnt[3]))|(cnt[4]&(~cnt[2]))|((~cnt[4])&cnt[3]&cnt[2]&cnt[1]));
light[4]<=(((~cnt[4])&cnt[3]&(~cnt[2])&cnt[1]&cnt[0])|((~cnt[4])&cnt[3]&cnt[2]&(~cnt[1])));
light[2]<=(((~cnt[4])&(~cnt[3]))|((~cnt[4])&(~cnt[2]))|((~cnt[4])&cnt[2]&(~cnt[1])));
light[1]<=((cnt[4]&cnt[3]&(~cnt[2])&cnt[0])|(cnt[4]&cnt[3]&(~cnt[2])&cnt[1]));
light[3]<=(((~cnt[4])&(~cnt[3])&(~cnt[1]))|((~cnt[4])&(~cnt[3])&(~cnt[2]))|((~cnt[4])&(~cnt[2])&(~cnt[1])&(~cnt[0]))|((~cnt[4])&(~cnt[2])&cnt[1]&(~cnt[0]))|((~cnt[4])&(~cnt[3])&cnt[1]&(~cnt[0])));
light[0]<=((cnt[4]&(~cnt[3])&(~cnt[2]))|(cnt[4]&(~cnt[2])&(~cnt[1])&(~cnt[0]))|(cnt[4]&(~cnt[3])&(~cnt[1])&(~cnt[0]))|(cnt[4]&(~cnt[3])&cnt[1]&(~cnt[0]))|((~cnt[4])&cnt[3]&cnt[2]&cnt[1]));
	end
endmodule

该模块实现了一个基于计数器值的交通信号灯控制器。在给定时钟信号的上升沿触发下,通过组合逻辑电路计算出当前计数器值所对应的红、黄、绿三种灯的状态,并将其输出到light寄存器中。具体地说,该模块包含一个5位的输入计数器值cnt和一个6位的输出灯状态light,其中light[5:0]分别对应红、黄、绿三种灯的状态。通过在不同的计数器值下控制各个灯的状态变化,从而实现了基于计数器的交通信号灯控制功能。

毛刺的消除

在实现了基本的红绿灯代码后,发现执行的结果中存在“毛刺”现象。
首先,我们需要确定毛刺的来源。查阅资料,发现毛刺可能源于TLDecoder模块的always @(cnt)敏感性列表。因为当cnt发生变化时,所有的输出信号都会重新计算。这可能会导致不同信号之间的计算不同步,从而引入毛刺。为了解决这个问题,我们可以尝试使用同步的时钟信号来消除毛刺。
具体来说,我们可以将TLDecoder模块的输入信号添加一个时钟信号clk,然后将敏感性列表更改为posedge clk。这样,所有的输出信号都将在时钟的上升沿同步更新,从而消除可能的毛刺。不过,请注意,这将使输出信号的更新速度受到时钟频率的限制。请根据具体应用场景调整时钟频率以满足实际需求。

verilog代码如下
module HardwareCourse(clk,r1,g1,y1,r2,y2,g2);
	input clk;
	output r1,y1,g1,r2,y2,g2;
	wire[4:0] cnt;
	
	TLCounter u1(clk,cnt);
	TLDecoder u2(cnt,{r1,y1,g1,r2,y2,g2},clk);



endmodule

module TLCounter(clk,cnt);//0~27 循环计数
	input clk;
	output[4:0] cnt;
	reg[4:0] cnt=5'b00001;
	assign clr=~(cnt[0]&cnt[1]&(cnt[2])&cnt[3]&cnt[4]);
	
	always @(posedge clk)
	begin
		begin
		cnt[0] <= (~cnt[0]);
		cnt[1] <= (cnt[1] ^ cnt[0]);
		cnt[2] <= (cnt[2] ^ (cnt[0] & cnt[1]));
		cnt[3] <= (cnt[3] ^ (cnt[0] & cnt[1] & cnt[2]));
		cnt[4] <= (cnt[4] ^ (cnt[0] & cnt[1] & cnt[2] & cnt[3]));
		end
	end
endmodule

module TLDecoder(cnt,light,clk);
	input clk;
	input[4:0] cnt;
	output[5:0] light;
	reg[5:0] light=6'b001100;
	
	always @(posedge clk)
	begin
		light[5]<=((cnt[4]&(~cnt[3]))|(cnt[4]&(~cnt[2]))|((~cnt[4])&cnt[3]&cnt[2]&cnt[1]));
		light[4]<=(((~cnt[4])&cnt[3]&(~cnt[2])&cnt[1]&cnt[0])|((~cnt[4])&cnt[3]&cnt[2]&(~cnt[1])));
		//light[3]<=(((~cnt[4])&(~cnt[3]))|((~cnt[4])&(~cnt[2])&(~cnt[1]))|((~cnt[4])&(~cnt[2])&cnt[1]&(~cnt[0])));
		light[2]<=(((~cnt[4])&(~cnt[3]))|((~cnt[4])&(~cnt[2]))|((~cnt[4])&cnt[2]&(~cnt[1])));
		light[1]<=((cnt[4]&cnt[3]&(~cnt[2])&cnt[0])|(cnt[4]&cnt[3]&(~cnt[2])&cnt[1]));
		//light[0]<=((cnt[4]&(~cnt[3]))|(cnt[4]&(~cnt[2])&(~cnt[1])&(~cnt[0]))|((~cnt[4])&cnt[3]&cnt[2])&cnt[1]);
			
		light[3]<=(((~cnt[4])&(~cnt[3])&(~cnt[1]))|((~cnt[4])&(~cnt[3])&(~cnt[2]))|((~cnt[4])&(~cnt[2])&(~cnt[1])&(~cnt[0]))|((~cnt[4])&(~cnt[2])&cnt[1]&(~cnt[0]))|((~cnt[4])&(~cnt[3])&cnt[1]&(~cnt[0])));
		light[0]<=((cnt[4]&(~cnt[3])&(~cnt[2]))|(cnt[4]&(~cnt[2])&(~cnt[1])&(~cnt[0]))|(cnt[4]&(~cnt[3])&(~cnt[1])&(~cnt[0]))|(cnt[4]&(~cnt[3])&cnt[1]&(~cnt[0]))|((~cnt[4])&cnt[3]&cnt[2]&cnt[1]));
		
	end
endmodule

你可能感兴趣的:(硬件工程)