交通灯控制器的verilog实现

用状态机实现交通灯控制器,仿真通过,有代码以及testbench。


要求:

方向1是主干道,绿灯时间较长,交通灯状态循环为:

绿:40

黄:5

左:15

黄:5

红:55

方向2不是主干道,绿灯时间较少,交通灯状态循环为:

红:65

绿:30

黄:5

左:15

黄:5


 注意:

  1. 此处将两个交通灯的状态合在一起,从而便于对两个等进行同步控制。将两个灯的5个状态合为8个状态,即:

绿1:40

黄1:5

左1:15

黄1:5

绿2:30

黄2:5

左2:15

黄2:5

对状态转换以及输出控制采用组合逻辑,在调试的过程中也曾使用时序逻辑来实现,仿真发现各种时序混乱。

在状态转换控制中,在change有效后,马上将其清零,代码如下,这是为了便于控制,调试时,发现这样比较方便,其他方法易出错。

在仿真图上就看不到change有效过,但仿真图上的其他信号是正确的。

1     G2   : if(trigger)  
2                            nxt_state = G1;
3            else if(change)  
5                   begin
6                         change = 1'b0;
7                         nxt_state = Y2_1;

代码如下:

  1 module traffic_light(rst_n,
  2                             clk,
  3                             trigger, //触发信号,使得状态机进入循环
  4                             light1,
  5                             light2
  6                                  );
  7 input rst_n;
  8 input clk;
  9 input trigger;
 10 
 11 output [3:0] light1;   //4bit分别对应绿、黄、左、红灯
 12 output [3:0] light2;
 13 
 14 //灯亮时间
 15 parameter G1_T = 7'd40;  //方向1的亮灯时间
 16 parameter Y1_T = 7'd5;
 17 parameter L1_T = 7'd15;
 18 
 19 parameter G2_T = 7'd30;    //方向2的亮灯时间
 20 parameter Y2_T = 7'd5;
 21 parameter L2_T = 7'd15;
 22 
 23 //状态编码
 24 parameter IDLE = 4'd0;    //此处为了方便采用简单的binary编码,可用one-hot或gray提高性能
 25 parameter G1 = 4'd1;
 26 parameter Y1_1 = 4'd2;
 27 parameter L1 = 4'd3;
 28 parameter Y1_2 = 4'd4;
 29 
 30 parameter G2 = 4'd5;
 31 parameter Y2_1 = 4'd6;
 32 parameter L2 = 4'd7;
 33 parameter Y2_2 = 4'd8;
 34 
 35 reg [3:0] cur_state;
 36 reg [3:0] nxt_state;
 37 
 38 reg [3:0] light1;
 39 reg [3:0] light2;
 40 
 41 reg [3:0] light1_tmp;
 42 reg [3:0] light2_tmp;
 43 
 44 reg [6:0] light_t_tmp;
 45 reg [6:0] light_t;
 46 
 47 reg change;
 48 reg start;
 49 
 50 //状态寄存,时序逻辑
 51 always@(posedge clk)
 52     if(!rst_n)
 53         cur_state <= IDLE;
 54     else
 55         cur_state <= nxt_state;
 56 
 57 //状态转换,组合逻辑        
 58 always@(*)
 59     if(!rst_n)
 60         begin
 61             //start <= 1'b0;
 62             nxt_state = IDLE;
 63         end
 64     else  
 65         begin
 66             case(cur_state)
 67                 IDLE : //if(change) 
 68                         if(trigger)  //状态机通过trigger进入状态循环
 69                             begin
 70                                 //start <= 1'b1;  //start与计数值light_t_tmp是同步的,因此一同写在输出控制中 
 71                                 nxt_state = G1;  //状态变换由组合逻辑实现,采用阻塞赋值即=,而非<=
 72                             end
 73                 G1   : if(trigger)  
 74                             begin
 75                                 //start <= 1'b1;
 76                                 nxt_state = G1;
 77                             end
 78                         else if(change)  
 79                                 begin
 80                                     //start <= 1'b1;
 81                                     change = 1'b0;
 82                                     nxt_state = Y1_1;
 83                                 end
 84                 Y1_1 : if(trigger)  
 85                             begin
 86                                 //start <= 1'b1;
 87                                 nxt_state = G1;
 88                             end
 89                         else if(change)  
 90                             begin
 91                                 //start <= 1'b1;
 92                                 change = 1'b0;
 93                                 nxt_state = L1;
 94                             end
 95                 L1   : if(trigger)  
 96                             begin
 97                                 //start <= 1'b1;
 98                                 nxt_state = G1;
 99                             end
100                         else if(change)  
101                             begin
102                                 //start <= 1'b1;
103                                 change = 1'b0;
104                                 nxt_state = Y1_2;
105                             end
106                 Y1_2 : if(trigger)  
107                             begin
108                                 //start <= 1'b1;
109                                 nxt_state = G1;
110                             end
111                         else if(change)  
112                             begin
113                                 //start <= 1'b1;
114                                 change = 1'b0;
115                                 nxt_state = G2;
116                             end
117                 G2   : if(trigger)  
118                             begin
119                                 //start <= 1'b1;
120                                 nxt_state = G1;
121                             end
122                         else if(change)  
123                             begin
124                                 //start <= 1'b1;
125                                 change = 1'b0;
126                                 nxt_state = Y2_1;
127                             end
128                 Y2_1 : if(trigger)  
129                             begin
130                                 //start <= 1'b1;
131                                 nxt_state = G1;
132                             end
133                         else if(change)  
134                             begin
135                                 //start <= 1'b1;
136                                 change = 1'b0;
137                                 nxt_state= L2;
138                             end
139                 L2   : if(trigger)  
140                             begin
141                                 //start <= 1'b1;
142                                 nxt_state = G1;
143                             end
144                         else if(change)  
145                             begin
146                                 //start <= 1'b1;
147                                 change = 1'b0;
148                                 nxt_state = Y2_2;
149                             end
150                 Y2_2 : if(trigger)  
151                             begin
152                                 //start <= 1'b1;
153                                 nxt_state = G1;
154                             end
155                         else if(change)  
156                             begin
157                                 //start <= 1'b1;
158                                 change = 1'b0;
159                                 nxt_state = G1;
160                             end
161                 default : nxt_state = IDLE;
162             endcase
163         end        
164         
165 //输出控制,组合逻辑
166 //start与计数值light_t_tmp是同步的,因此一同写在输出控制中 
167 //always@(posedge clk)   //输出为组合逻辑,因此不在clk下动作
168 always@(*)
169     if(!rst_n)
170         begin
171             start = 1'b0;
172             light_t_tmp = 7'd0;
173             light1_tmp = 4'b0000;
174             light2_tmp = 4'b0000;
175         end
176     else case(cur_state)
177             G1   : begin
178                         start = 1'b1;
179                         light_t_tmp = G1_T;
180                         light1_tmp = 4'b1000;
181                         light2_tmp = 4'b0001;                    
182                      end
183             Y1_1 : begin
184                         start = 1'b1;
185                         light_t_tmp = Y1_T;
186                         light1_tmp = 4'b0100;
187                         light2_tmp = 4'b0001;                
188                      end
189             L1   : begin
190                         start = 1'b1;
191                         light_t_tmp = L1_T;
192                         light1_tmp = 4'b0010;
193                         light2_tmp = 4'b0001;                
194                      end
195             Y1_2 : begin
196                         start = 1'b1;
197                         light_t_tmp = Y1_T;
198                         light1_tmp = 4'b0100;
199                         light2_tmp = 4'b0001;                
200                      end
201             G2   : begin
202                         start = 1'b1;
203                         light_t_tmp = G2_T;
204                         light1_tmp = 4'b0001;
205                         light2_tmp = 4'b1000;                
206                      end
207             Y2_1 : begin
208                         start = 1'b1;
209                         light_t_tmp = Y2_T;
210                         light1_tmp = 4'b0001;
211                         light2_tmp = 4'b0100;                
212                      end
213             L2   : begin
214                         start = 1'b1;
215                         light_t_tmp = L2_T;
216                         light1_tmp = 4'b0001;
217                         light2_tmp = 4'b0010;                
218                      end
219             Y2_2 : begin
220                         start = 1'b1;
221                         light_t_tmp = Y2_T;
222                         light1_tmp = 4'b0001;
223                         light2_tmp = 4'b0100;                
224                      end
225         endcase
226 
227 //灯亮时间倒计时
228 //时序逻辑,要在clk时钟下动作
229 always@(posedge clk)
230     if(!rst_n)
231         begin
232             light_t <= 7'd0;
233         end
234     else if(start)
235                 begin
236                     start <= 1'b0;
237                     light_t <= light_t_tmp;
238                 end
239          else
240             begin
241                 light_t <= light_t - 1'b1;
242             end
243             
244 //在light_t减到2时,置为change信号
245 //用组合逻辑
246 always@(*)
247     if(!rst_n)
248         change = 1'b0;  
249     else if(light_t == 4'd2)
250         change = 1'b1;
251         
252 //输出寄存    
253 always@(posedge clk)
254     if(!rst_n)
255         begin
256             light1 <= 4'd0;
257             light2 <= 4'd0;
258         end
259     else
260         begin
261             light1 <= light1_tmp;
262             light2 <= light2_tmp;
263         end
264         
265 //下面是调试过程中对change以及start的控制    
266 //因为使用了时序逻辑,导致各种错误
267 /*
268 always@(posedge clk)
269     if(!rst_n)
270         begin
271             light_t <= 7'd0;
272             //change <= 1'b0;  //复位,开始状态转换
273         end
274     else if(start)
275                 begin
276                     start <= 1'b0;
277                     //change <= 1'b0;
278                     //change_r <= 1'b0;
279                     light_t <= light_t_tmp;
280                 end
281             //else if(light_t == 4'd1)
282             //        change <= 1'b1;
283                  else
284                     begin
285                         light_t <= light_t - 1'b1;
286                         //change <= 1'b0;
287                     end
288 */
289             
290 /*            
291 always@(*)
292     if(!rst_n)
293         change = 1'b0;  //复位,开始状态转换
294     else if(start)
295             change = 1'b0;
296         else if(light_t == 4'd1)
297         else if(light_t == 4'd2)
298             change = 1'b1;        
299 */    
300 
301 endmodule

testbench如下:

 1 module traffic_light_tb;
 2 
 3     // Inputs
 4     reg rst_n;
 5     reg clk;
 6     reg trigger;
 7 
 8     // Outputs
 9     wire [3:0] light1;
10     wire [3:0] light2;
11 
12     // Instantiate the Unit Under Test (UUT)
13     traffic_light uut (
14         .rst_n(rst_n), 
15         .clk(clk), 
16         .trigger(trigger),
17         .light1(light1), 
18         .light2(light2)
19     );
20     
21     parameter CLK_PERIOD = 10;
22 
23     initial begin
24         rst_n = 0;
25         clk = 1;
26         trigger = 0;
27 
28         #100;    
29         rst_n = 1;
30         trigger = 1;   //初始给出trigger信号,使得状态机进行状态循环
31         #CLK_PERIOD trigger = 0;
32         
33         //#1000 trigger = 1;  //trigger复位状态机
34         //#100 trigger = 0;
35         
36     end
37     
38     always #(CLK_PERIOD/2) clk = ~clk;
39       
40 endmodule

ISIM仿真结果:

可以看到,两个交通灯从给定的状态间循环,且时间同步。

原文地址:https://www.cnblogs.com/youngforever/p/3119497.html