实现功能:十字路口A和B两个方向用红灯20秒、黄灯5秒、绿灯9秒的方式变化,数码管同时倒计时显示通行或禁止通行时间。
所需模块:
1.数码管动态扫描子模块
2.数码管显示子模块
3.1秒时钟产生子模块
4.9s-5s-20s-20s顺序计时子模块
5.20s-20s-9s-5s顺序计时子模块
6.mealy四状态机子模块
7.顶层运用模块
应用原理及方法:
状态机:MOORE状态机、MEALY状态机
仿真:
1.将各个功能模块化,分别测试各个模块的功能是否正确。
2.仿真初值设置,采用rst按键复位产生初值。
代码:
顶层模块:
module main(clk,dig,rst,seg,ledA,ledB);
input clk;
output ledA,ledB;
input rst;
output dig;
output seg;
wire [3:0]dig;
wire [7:0]seg;
wire [2:0]ledA,ledB;
wire clk_1Hz;//1Hz
wire clkA,clkB;//15s
wire clk_scan;//动态扫描频率
wire [3:0]cntA_1,cntA_2;
wire [3:0]cntB_1,cntB_2;
CLK_1S CLK1S(.clk_100MHz(clk),.clk_1Hz(clk_1Hz));//产生1Hz时钟
CLK_A A1(.clk_1Hz(clk_1Hz),.clk_out(clkA),.cnt_1(cntA_1),.cnt_2(cntA_2));//产生周期为15秒时钟
CLK_B B1(.clk_1Hz(clk_1Hz),.clk_out(clkB),.cnt_1(cntB_1),.cnt_2(cntB_2));
CLK_SCAN S1(.clk_100MHz(clk),.clk_scan(clk_scan));//产生3KHz扫描时钟
DIG_SEG D1(.clk_sel(clk_scan),.dig(dig),.seg(seg),.seg1(cntB_2),.seg2(cntB_1),.seg3(cntA_2),.seg4(cntA_1));//数码管显示
STATEA L1(.clk_in(clkA),.rst(rst),.currentstate(ledA));
STATEB L2(.clk_in(clkB),.rst(rst),.currentstate(ledB));
endmodule
1秒时钟产生子模块:
BASYS 3的时钟为100MHz,100M个周期,即是一秒。T=1S时,0.5S反转一次。所以这里用到一个cnt,计数50M满,1s输出信号跳变,cnt==28'b10111110101111000010000000,50 000 000。
//时钟分频模块:将Basys3上的100MHz时钟clk分频到1Hz输出,作为15秒倒计时计数时钟clk_1hz ;
module CLK_1S(clk_100MHz,clk_1Hz);
input clk_100MHz;//100M时钟输入
output reg clk_1Hz;//输出1s
reg [27:0] cnt;
always @(posedge clk_100MHz)
begin
if(cnt==28'b0010_1111_1010_1111_0000_1000_0000)//100MHz/1Hz
begin
cnt <=0;//清零
clk_1Hz <= ~clk_1Hz;
end
else
cnt <= cnt + 1;
end
endmodule
9s-5s-20s-20s顺序计时子模块:
module CLK_A(clk_1Hz,clk_out,cnt_1,cnt_2);
input clk_1Hz;//1s
output reg clk_out;//15s
output cnt_1,cnt_2;//两位记数 0-9
reg [4:0]cnt;//0-15
wire [3:0]cnt_1;//十位
wire [3:0]cnt_2;//个位
reg [1:0]sig;
assign cnt_1 =cnt/'b1010; //十位除10
assign cnt_2 =cnt%'b1010;//各位余10
always @(posedge clk_1Hz)//产生两位数
begin
if(cnt==5'b00000||cnt==5'b11111)begin // cnt0-14 不需要到达1
case(sig)
2'b00:begin
cnt<=5'b01001; //9
sig<=sig+'b1;
clk_out<=1;
end
2'b01:begin
cnt<=5'b00101; //5
sig<=sig+'b1;
clk_out<=1;
end
2'b10:begin
cnt<=5'b10100; //20
sig<=sig+'b1;
clk_out<=1;
end
2'b11:begin
cnt<=5'b10100; //20
sig<=sig+'b1;
clk_out<=1;
end
endcase
end
else begin
cnt <= cnt -'b1;
clk_out<=0;
end
end
endmodule
20s-20s-9s-5s顺序计时子模块:
module CLK_B(clk_1Hz,clk_out,cnt_1,cnt_2);
input clk_1Hz;//1s
output reg clk_out;//15s
output cnt_1,cnt_2;//两位记数 0-9
reg [4:0]cnt;//0-15
wire [3:0]cnt_1;//十位
wire [3:0]cnt_2;//个位
reg [1:0]sig;
assign cnt_1 =cnt/'b1010; //十位除10
assign cnt_2 =cnt%'b1010;//各位余10
always @(posedge clk_1Hz)//产生两位数
begin
if(cnt==5'b00000||cnt==5'b11111)begin // cnt0-14 不需要到达1
case(sig)
2'b00:begin
cnt<=5'b10100; //20
sig<=sig+'b1;
clk_out<=1;
end
2'b01:begin
cnt<=5'b10100; //20
sig<=sig+'b1;
clk_out<=1;
end
2'b10:begin
cnt<=5'b01001; //9
sig<=sig+'b1;
clk_out<=1;
end
2'b11:begin
cnt<=5'b00101; //5
sig<=sig+'b1;
clk_out<=1;
end
endcase
end
else begin
cnt <= cnt -'b1;
clk_out<=0;
end
end
endmodule
数码管动态扫描子模块:
//100MHz分频到2.5KHz~4KHz输出,作为数码管动态显示的扫描频率clk-scan,3Khz动态扫描
module CLK_SCAN(clk_100MHz,clk_scan);
input clk_100MHz;
output reg clk_scan;
reg [15:0] cnt;
always @(posedge clk_100MHz)
begin
cnt <= cnt + 1;
if(cnt==16'b1000_0010_0011_0101)//100MHz/33333Hz
begin
cnt <=0;//清零
clk_scan <= ~clk_scan;
end
end
endmodule
数码管显示子模块:
odule DIG_SEG(clk_sel,seg1,seg2,seg3,seg4,dig,seg);
input clk_sel;
input [3:0]seg1,seg2,seg3,seg4;
output dig,seg;
reg [3:0]dig;
reg [7:0]seg;
reg [1:0]selcnt;
//parameter seg_0=8'b11000000;
//parameter seg_1=8'b11111001;
//parameter seg_2=8'b10100100;
//parameter seg_3=8'b10110000;
//parameter seg_4=8'b10011001;
//parameter seg_5=8'b10010010;
//parameter seg_6=8'b10000010;
//parameter seg_7=8'b11111000;
//parameter seg_8=8'b10000000;
//parameter seg_9=8'b10010000;
always @(posedge clk_sel)//位选标志位
begin
selcnt <= selcnt + 1;//标志位+1,11记满后加一回到00
end
always @(selcnt) //位选信号控制
begin
case (selcnt)
2'b00: begin dig <= 4'b0111;end //1号数码管显示ain对应的段码
2'b01: begin dig <= 4'b1011;end
2'b10: begin dig <= 4'b1101;end
2'b11: begin dig <= 4'b1110;end
endcase
end
always @(selcnt or seg1 or seg2 or seg3 or seg4) //位选信号控制
begin
if (selcnt==2'b00)
begin
case(seg1)
4'b0000:seg <= 8'b11000000;
4'b0001:seg <= 8'b11111001;
4'b0010:seg <= 8'b10100100;
4'b0011:seg <= 8'b10110000;
4'b0100:seg <= 8'b10011001;
4'b0101:seg <= 8'b10010010;
4'b0110:seg <= 8'b10000010;
4'b0111:seg <= 8'b11111000;
4'b1000:seg <= 8'b10000000;
4'b1001:seg <= 8'b10010000;
default: seg<=8'b11000000;
endcase
end
if (selcnt==2'b01)
begin
case(seg2)
4'b0000:seg <= 8'b11000000;
4'b0001:seg <= 8'b11111001;
4'b0010:seg <= 8'b10100100;
4'b0011:seg <= 8'b10110000;
4'b0100:seg <= 8'b10011001;
4'b0101:seg <= 8'b10010010;
4'b0110:seg <= 8'b10000010;
4'b0111:seg <= 8'b11111000;
4'b1000:seg <= 8'b10000000;
4'b1001:seg <= 8'b10010000;
default: seg<=8'b11000000;
endcase
end
if (selcnt==2'b10)
begin
case(seg3)
4'b0000:seg <= 8'b11000000;
4'b0001:seg <= 8'b11111001;
4'b0010:seg <= 8'b10100100;
4'b0011:seg <= 8'b10110000;
4'b0100:seg <= 8'b10011001;
4'b0101:seg <= 8'b10010010;
4'b0110:seg <= 8'b10000010;
4'b0111:seg <= 8'b11111000;
4'b1000:seg <= 8'b10000000;
4'b1001:seg <= 8'b10010000;
default: seg<=8'b11000000;
endcase
end
if (selcnt==2'b11)
begin
case(seg4)
4'b0000:seg <= 8'b11000000;
4'b0001:seg <= 8'b11111001;
4'b0010:seg <= 8'b10100100;
4'b0011:seg <= 8'b10110000;
4'b0100:seg <= 8'b10011001;
4'b0101:seg <= 8'b10010010;
4'b0110:seg <= 8'b10000010;
4'b0111:seg <= 8'b11111000;
4'b1000:seg <= 8'b10000000;
4'b1001:seg <= 8'b10010000;
default: seg<=8'b11000000;
endcase
end
end
endmodule
A路状态机:利用sig标志位控制红灯亮两次,sig=0,为红灯时,状态不跳转,红灯显示一次,sig加1。sig=1,为红灯时,状态下一次翻转。
module STATEA(clk_in,rst,currentstate);
input clk_in;
input rst;
output reg [2:0]currentstate;
reg [2:0]nextstate;
reg sig;
parameter S0=3'b001;
parameter S1=3'b010;
parameter S2=3'b100;
always @(posedge clk_in or posedge rst)
begin
if(rst)
currentstate<=S0;
else begin
currentstate<=nextstate;
if(currentstate==S2)
sig<=sig+1;
end
end
always @(currentstate or sig)
begin
case(currentstate)
S0:nextstate=S1;
S1:nextstate=S2;
S2:begin
if(sig)
nextstate=S0;
else
nextstate=S2;
end
default: nextstate=S1;
endcase
end
endmodule
B路状态机:
module STATEB(clk_in,rst,currentstate);
input clk_in;
input rst;
output reg [2:0]currentstate;
reg [2:0]nextstate;
reg sig;
parameter S0=3'b001;
parameter S1=3'b010;
parameter S2=3'b100;
always @(posedge clk_in or posedge rst)
begin
if(rst)
currentstate<=S2;
else begin
currentstate<=nextstate;
if(currentstate==S2)
sig<=sig+1;
end
end
always @(currentstate or sig)
begin
case(currentstate)
S0:nextstate=S1;
S1:nextstate=S2;
S2:begin
if(sig)
nextstate=S0;
else
nextstate=S2;
end
default: nextstate=S1;
endcase
end
endmodule
工程文件实例:
代码改进,若需要不同时间的红绿灯,只需要重新设置在顺序计时模块中的时间条件即可。
红绿灯系统的目标是优化交通流量,提高交通效率和安全性。单个的红绿灯设计可以帮助我们对状态机的理解。
但是在实际生活中,红绿灯是一个庞大的系统,一条主干道上有很多的红绿灯,需要对实际路况和车流量和道路宽窄设计转换时间,并且需要和多个红绿灯协同运作。这样的设计才能解决实际性问题。
当然,现代的红绿灯系统已经很完善了,缺少的是对路况和人车流量的智能检测和分析。