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