4. 用状态机设计交通灯控制器,设计要求:A路和B路,每路都有红、黄、绿三种灯,持续时间为:红灯45s,黄灯5s,绿灯40秒。
A路和B路灯的状态转换是:
(1) A红,B绿(持续时间40s);
(2) A红,B黄(持续时间5s);
(1) A绿,B红(持续时间40s);
(1) A绿,B黄(持续时间5s);
4.1 设计思路:
由题知共4个状态,每个状态及其输出持续的时间分别为40s或5秒。故设计一个模为90的计数器,分4段,对应每个状态持续的
时间,然后顺序循环。
4.2 两路交通灯控制电路源码如下:
1 //triffic lights 2 //ex8_4 3 //2020-10-14 4 //by YongFengXie 5 module ex8_4(clk,rst_n,lights); 6 input clk; 7 input rst_n; 8 output reg [5:0] lights; //A and B light 9 10 reg [6:0] cnt; // counter 90 11 reg [3:0] state; 12 13 parameter s0=4'b0001,s1=4'b0010,s2=4'b0100, 14 s3=4'b1000; 15 16 always @(posedge clk or negedge rst_n) 17 begin 18 if(!rst_n) 19 cnt<=7'd0; 20 else if(cnt<7'd90) 21 cnt<=cnt+1'b1; 22 else 23 cnt<=7'd0; 24 end 25 26 always @(posedge clk or negedge rst_n) 27 begin 28 if(!rst_n) 29 begin 30 state<=s0; 31 lights<=6'b100_001; 32 end 33 else if(cnt<7'd40) 34 begin 35 state<=s0; 36 lights<=6'b100_001; //RYG(A)_RYG(B) 37 end 38 else if(cnt>7'd39 &&cnt<7'd45) 39 begin 40 state<=s1; 41 lights<=6'b100_010; //RYG(A)_RYG(B) 42 end 43 else if(cnt>7'd44 && cnt<7'd85) 44 begin 45 state<=s2; 46 lights<=6'b001_100; //RYG(A)_RYG(B) 47 end 48 else 49 begin 50 state<=s3; 51 lights<=6'b001_010; //RYG(A)_RYG(B) 52 end 53 end 54 55 endmodule
4.3 交通灯控制器的测试代码:
1 //ex8_4 testbench 2 //2020-10-14 3 //by YongFengXie 4 `timescale 1ns/1ns 5 module ex8_4tb; 6 reg clk; 7 reg rst_n; 8 wire [5:0] lights; 9 10 ex8_4 ub(clk,rst_n,lights); 11 12 initial begin 13 clk=1'b0; 14 rst_n=1'b0; 15 #20 rst_n=1'b1; 16 #1000 $stop; 17 end 18 19 always #5 clk=~clk; 20 21 endmodule
4.4 交通灯控制器的仿真结果如图ex8_4_1所示:
图ex8_4_1 交通灯控制器仿真结果
4.5 总结:交通灯控制器这个电路的状态转换挺简单,题目里已经详细列出。难在每种状态持续时间不一样,这是跟前面的序列检测不同的地 方。按照上述设计,在Quartus里未生成状态转换图,仿真和DE2-115上皆可验证正确。期待更好的解法。
4.6 参照https://blog.csdn.net/qq_38318540/article/details/107401152,找到方法,计时模块,状态转换,状态输出,条理清晰的分开写,难点在 于计数器还是只需要一个,控制模不同即可,产生计时的效果,也就是需要40s,5s的计时,设计里在状态发生转换时产生一个标志st,同时 这个st,在计时模块里又扮演计数器清零的一个功能,达到计时到不同值,计数器清零重新开始计数的目的,看似无用的st,关联器状态变化
的节奏。
另一种交通灯控制器的Verilog代码如下:
1 //triffic lights 2 //ex8_4 3 //2020-10-14 4 //by YongFengXie 5 module ex8_4(clk,rst_n,lights); 6 input clk; 7 input rst_n; 8 output reg [5:0] lights; //A and B light 9 10 reg [6:0] cnt; // counter 90 11 reg [3:0] state,nextstate; 12 wire t1,t2; // t1-40s,t2-5s 13 reg st; // state transition signal 14 15 parameter s0=4'b0001,s1=4'b0010,s2=4'b0100, 16 s3=4'b1000; 17 18 //timing module 19 always @(posedge clk or negedge rst_n) 20 begin 21 if(!rst_n) 22 cnt<=7'd0; 23 else if(st) 24 cnt<=7'd0; 25 else if(cnt<7'd40) 26 cnt<=cnt+1'b1; 27 else 28 cnt<=7'd0; 29 end 30 31 assign t1=(cnt==7'd39)?1'b1:1'b0; 32 assign t2=(cnt==7'd4)?1'b1:1'b0; 33 34 /* 35 always @(posedge clk or negedge rst_n) 36 begin 37 if(!rst_n) 38 begin 39 state<=s0; 40 lights<=6'b100_001; 41 end 42 else if(cnt<7'd40) 43 begin 44 state<=s0; 45 lights<=6'b100_001; //RYG(A)_RYG(B) 46 end 47 else if(cnt>7'd39 &&cnt<7'd45) 48 begin 49 state<=s1; 50 lights<=6'b100_010; //RYG(A)_RYG(B) 51 end 52 else if(cnt>7'd44 && cnt<7'd85) 53 begin 54 state<=s2; 55 lights<=6'b001_100; //RYG(A)_RYG(B) 56 end 57 else 58 begin 59 state<=s3; 60 lights<=6'b001_010; //RYG(A)_RYG(B) 61 end 62 end 63 */ 64 65 //state transition module 66 always @(posedge clk or negedge rst_n) 67 begin 68 if(!rst_n) 69 state<=s0; 70 else 71 state<=nextstate; 72 end 73 74 always @(state,t1,t2) 75 begin 76 case(state) 77 s0: begin 78 nextstate<=t1?s1:s0; 79 st<=t1?1'b1:1'b0; 80 end 81 s1: begin 82 nextstate<=t2?s2:s1; 83 st<=t2?1'b1:1'b0; 84 end 85 s2: begin 86 nextstate<=t1?s3:s2; 87 st<=t1?1'b1:1'b0; 88 end 89 s3: begin 90 nextstate<=t2?s0:s3; 91 st<=t2?1'b1:1'b0; 92 end 93 default: begin 94 nextstate<=s0; 95 st<=1'b0; 96 end 97 endcase 98 end 99 100 //state corresponding output 101 always @(state) 102 begin 103 case(state) 104 s0:lights=6'b100_001; //A-R,B-G 105 s1:lights=6'b100_010; //A-R,B-Y 106 s2:lights=6'b001_100; //A-G,B-R 107 s3:lights=6'b010_100; //A-Y,B-R 108 default:lights=6'b100_001; //A-R,B-G 109 endcase 110 end 111 112 endmodule
上面的代码不够简洁,还是有个固定思维的问题,其中从18行开始的计时模块做成模可变的计数器更优,所以,这段,修改如下:
1 //timing module 2 always @(posedge clk or negedge rst_n) 3 begin 4 if(!rst_n) 5 cnt<=7'd0; 6 else if(st) 7 cnt<=7'd0; 8 else 9 cnt<=cnt+1'b1; 10 /*else if(cnt<7'd40) 11 cnt<=cnt+1'b1; 12 else 13 cnt<=7'd0;*/ 14 end