【案例】状态机实现LED交通灯设计

  发布时间:2023-10-19  |    作者:管理员  |  浏览量:1058

本文为明德扬原创及录用文章,转载请注明出处!

1.1 总体设计

1.1.1 概述

发光二极管简称为LED,是一种常用的发光器件,通过电子与空穴复合释放能量发光,可以高效的将电能转化为光能,在现代社会具有广泛的用途,如照明、平板显示、医疗器件等。可通过高低电平的变化来控制LED灯的明灭状态,当输出信号为低电平时,LED灯亮,反之,当输出信号为高电平时,LED灯灭。


1.1.2 设计目标

内容:开发板上有红黄绿 LED 灯各四个,分别放在东西南北方向。参考交通灯的情况,即每个方向都是绿灯亮 10 秒,然后黄灯亮 5 秒,然后红灯亮 15 秒。绿灯按照东西和南北的顺序依次亮。

具体思路:

1. 首先分东西方向和南北方向来设计电路。设计两个不同的状态机来指示不同的状态。东西方向的灯状态相同,南北方向的灯状态相同。

2. 4个方向的灯依次为红绿黄的依次循环时间为 15+10+5=30 秒,所以可以设计一个计数器,计时 30 秒钟,表示一个循环。计数器可以分两个写,一个计时 1秒,一个计时 30秒。

3. 然后再根据计数器的计数值的不同,决定状态机的不同状态。

4. 首先设计东西方向的状态机,复位的时候,绿灯亮,计数器计到 10 秒,黄灯亮,计到15 秒,红灯亮,计满 30 秒,又是绿灯亮......依次循环。

5. 接着设计南北方向的状态机,复位的时候,红灯亮,计数器计到15 秒,绿灯亮,计到20 秒,黄灯亮,计满 30 秒,又是红灯亮......依次循环。


1.1.3信号列表

「每周FPGA案例」状态机实现的LED交通灯2


1.1.4 设计思路

根据题目功能要求,东西南北四个方向LED灯按照“红灯-绿灯-黄灯”的顺序依次循环时间为 15+10+5=30 秒,所以可以设计一个计数器,计时 30 秒钟表示一个循环。该计数器可以分两个写,一个计时 1 秒,一个计时 30秒。

因为在数字电路中的延时都是通过计数器实现的,计数器*时钟周期=延时时间。本模块中,由于输入时钟是50MHz,时钟周期为20ns,功能要求每1秒变化一次。我们通过counter来表示延时,当其值为1s/20ns=5000_0000时,表示1秒时间到。

两个计数器的架构图:

「每周FPGA案例」状态机实现的LED交通灯2

时钟计数器counter:该计数器用于计算1s的时钟个数,加一条件为1,表示一直计数;数到5000_0000下,则表示数到1秒的时间了。

秒计数器:该计数器用于计算1个周期内三色LED按顺序各点亮1次的时间,1周期的时间为30秒,加一条件为时钟计数器的结束条件,表示时钟计数器每数完1s,秒计数器计数加一;数到30下,则表示数到30秒的时间了。

下面是两个计数器的代码:

1.	parameter   COUNT_TIME      =   26'd5000_0000;
2.	parameter   CYCLE_TIME       =   5'd30        ;
3.	parameter   COUNT_WID       =   26           ;
4.	parameter   SEC_WID          =   5            ;
5.	
6.	reg     [COUNT_WID-1:0] counter             ;
7.	wire                    add_counter         ;
8.	wire                    end_counter         ;
9.	reg     [SEC_WID-1:0]    second             ;
10.	wire                    add_second          ;
11.	wire                    end_second          ;
12.	
13.	always @(posedge clk or negedge rst_n) begin 
14.	    if (rst_n==0) begin
15.	        counter <= 0; 
16.	    end
17.	    else if(add_counter) begin
18.	        if(end_counter)
19.	            counter <= 0; 
20.	        else
21.	            counter <= counter+1 ;
22.	   end
23.	end
24.	assign add_counter = 1;
25.	assign end_counter = add_counter  && counter == COUNT_TIME-1 ;
26.	
27.	
28.	always @(posedge clk or negedge rst_n) begin 
29.	    if (rst_n==0) begin
30.	        second <= 0; 
31.	    end
32.	    else if(add_second) begin
33.	        if(end_second)
34.	            second <= 0; 
35.	        else
36.	            second <= second+1 ;
37.	   end
38.	end
39.	assign add_second = end_counter;
40.	assign end_second = add_second  && second == CYCLE_TIME-1 ;



按照题目要求:分东西方向和南北方向来设计电路,因此设计两个不同的状态机来指示不同的状态——同一时间内,东西方向的灯状态相同,南北方向的灯状态相同。

两个状态机的架构:

「每周FPGA案例」状态机实现的LED交通灯2
「每周FPGA案例」状态机实现的LED交通灯2

东西方向的状态机:该状态机用于设定东西方向LED的颜色跳转状态。

1) 上电后,就跳转到绿灯亮状态,绿灯亮;

2) 10 秒后,黄灯亮,跳转条件为秒计数器计数10下,即add_second &&second==10-1,则表示数到10秒了;

3) 5 秒后,红灯亮,跳转条件为秒计数器计数15下,即add_second &&second==15-1,则表示数到15秒了;

4) 15 秒后,又是绿灯亮,跳转条件为秒计数器计满30下,即add_second &&second==30-1,则表示数到30秒了......依次循环。

南北方向的状态机:该状态机用于设定南北方向LED的颜色跳转状态。

1) 上电后,就跳转到红灯亮状态,红灯亮;

2) 15 秒后,绿灯亮,跳转条件为秒计数器计数15下,即add_second &&second==15-1,则表示数到15秒了;

3) 10 秒后,黄灯亮,跳转条件为秒计数器计数25下,即add_second &&second==25-1,则表示数到25秒了;

4) 5 秒后,又是红灯亮,跳转条件为秒计数器计满30下,即add_second &&second==30-1,则表示数到30秒了......依次循环。

下面是东西、南北方向的两个状态机代码:

41.	parameter   LED_NUM         =   3            ;
42.	parameter   STA_W            =   2            ;
43.	
44.	parameter   STA_G           =   2'd1         ;
45.	parameter   STA_Y           =   2'd2         ;
46.	parameter   STA_R           =   2'd3         ;
47.	parameter   IDLE            =   2'd0         ;
48.	parameter   GREEN          =   3'b110       ;
49.	parameter   YELLOW         =   3'b101       ;
50.	parameter   RED             =   3'b011       ;
51.	
52.	input                   clk                 ;
53.	input                   rst_n               ;
54.	output  [LED_NUM-1:0]   led_east            ;
55.	output  [LED_NUM-1:0]   led_south           ;
56.	output  [LED_NUM-1:0]   led_west            ;
57.	output  [LED_NUM-1:0]   led_north           ;
58.	
59.	reg     [LED_NUM-1:0]   led_east            ;
60.	reg     [LED_NUM-1:0]   led_south           ;
61.	reg     [LED_NUM-1:0]   led_west            ;
62.	reg     [LED_NUM-1:0]   led_north           ;
63.	
64.	reg     [STA_W-1:0]     ew_state_c            ;
65.	reg     [STA_W-1:0]     ew_state_n            ;
66.	wire                    idle2sta_g_start_ew   ;
67.	wire                    sta_g2sta_y_start_ew  ;
68.	wire                    sta_y2sta_r_start_ew  ;
69.	wire                    sta_r2sta_g_start_ew  ;
70.	
71.	reg     [STA_W-1:0]     sn_state_c            ;
72.	reg     [STA_W-1:0]     sn_state_n            ;
73.	wire                    idle2sta_r_start_sn   ;
74.	wire                    sta_r2sta_g_start_sn  ;
75.	wire                    sta_g2sta_y_start_sn  ;
76.	wire                    sta_y2sta_r_start_sn  ;
77.	
78.	always @(posedge clk or negedge rst_n) begin 
79.	    if (rst_n==0) begin
80.	        ew_state_c <= STA_G ;
81.	    end
82.	    else begin
83.	        ew_state_c <= ew_state_n;
84.	   end
85.	end
86.	
87.	always @(*) begin 
88.	    case(ew_state_c)  
89.	        STA_G :begin
90.	            if(sta_g2sta_y_start_ew) 
91.	                ew_state_n = STA_Y ;
92.	            else 
93.	                ew_state_n = ew_state_c ;
94.	        end
95.	        STA_Y :begin
96.	            if(sta_y2sta_r_start_ew) 
97.	                ew_state_n = STA_R ;
98.	            else 
99.	                ew_state_n = ew_state_c ;
100.	        end
101.	        STA_R :begin
102.	            if(sta_r2sta_g_start_ew) 
103.	                ew_state_n = STA_G ;
104.	            else 
105.	                ew_state_n = ew_state_c ;
106.	        end
107.	        default : ew_state_n = STA_G ;
108.	    endcase
109.	end
110.	
111.	assign sta_g2sta_y_start_ew = ew_state_c==STA_G && add_second  && second == 10-1;
112.	assign sta_y2sta_r_start_ew = ew_state_c==STA_Y && add_second  && second == 15-1;
113.	assign sta_r2sta_g_start_ew = ew_state_c==STA_R && add_second  && second == 30-1;
114.	
115.	always  @(posedge clk or negedge rst_n)begin
116.	    if(rst_n==1'b0)begin
117.	        led_east<=GREEN; 
118.	    end
119.	    else if(ew_state_c==STA_G)begin
120.	        led_east<=GREEN;
121.	    end
122.	    else if(ew_state_c==STA_Y)begin
123.	        led_east<=YELLOW;
124.	    end
125.	    else if(ew_state_c==STA_R)begin
126.	        led_east<=RED;
127.	    end
128.	    else begin
129.	        led_east<=GREEN;
130.	    end
131.	end
132.	
133.	always  @(posedge clk or negedge rst_n)begin
134.	    if(rst_n==1'b0)begin
135.	        led_west<=GREEN; 
136.	    end
137.	    else if(ew_state_c==STA_G)begin
138.	        led_west<=GREEN;
139.	    end
140.	    else if(ew_state_c==STA_Y)begin
141.	        led_west<=YELLOW;
142.	    end
143.	    else if(ew_state_c==STA_R)begin
144.	        led_west<=RED;
145.	    end
146.	    else begin
147.	        led_west<=GREEN;
148.	    end
149.	end
150.	
151.	
152.	
153.	always @(posedge clk or negedge rst_n) begin 
154.	    if (rst_n==0) begin
155.	        sn_state_c <= STA_R ;
156.	    end
157.	    else begin
158.	        sn_state_c <= sn_state_n;
159.	   end
160.	end
161.	
162.	always @(*) begin 
163.	    case(sn_state_c)  
164.	        STA_R :begin
165.	            if(sta_r2sta_g_start_sn) 
166.	                sn_state_n = STA_G ;
167.	            else 
168.	                sn_state_n = sn_state_c ;
169.	        end
170.	        STA_G :begin
171.	            if(sta_g2sta_y_start_sn) 
172.	                sn_state_n = STA_Y ;
173.	            else 
174.	                sn_state_n = sn_state_c ;
175.	        end
176.	        STA_Y :begin
177.	            if(sta_y2sta_r_start_sn) 
178.	                sn_state_n = STA_R ;
179.	            else 
180.	                sn_state_n = sn_state_c ;
181.	        end
182.	        default : sn_state_n = STA_R ;
183.	    endcase
184.	end
185.	
186.	assign sta_r2sta_g_start_sn = sn_state_c==STA_R && add_second  && second == 15-1;
187.	assign sta_g2sta_y_start_sn = sn_state_c==STA_G && add_second  && second == 25-1;
188.	assign sta_y2sta_r_start_sn = sn_state_c==STA_Y && add_second  && second == 30-1;
189.	
190.	always  @(posedge clk or negedge rst_n)begin
191.	    if(rst_n==1'b0)begin
192.	        led_south<=RED; 
193.	    end
194.	    else if(sn_state_c==STA_G)begin
195.	        led_south<=GREEN;
196.	    end
197.	    else if(sn_state_c==STA_Y)begin
198.	        led_south<=YELLOW;
199.	    end
200.	    else if(sn_state_c==STA_R)begin
201.	        led_south<=RED;
202.	    end
203.	    else begin
204.	        led_south<=GREEN;     
205.	    end
206.	end
207.	
208.	always  @(posedge clk or negedge rst_n)begin
209.	    if(rst_n==1'b0)begin
210.	        led_north<=RED; 
211.	    end
212.	    else if(sn_state_c==STA_G)begin
213.	        led_north<=GREEN;
214.	    end
215.	    else if(sn_state_c==STA_Y)begin
216.	        led_north<=YELLOW;
217.	    end
218.	    else if(sn_state_c==STA_R)begin
219.	        led_north<=RED;
220.	    end
221.	    else begin
222.	        led_north<=GREEN;   
223.	    end
224.	end



1.1.5参考设计代码

225.	/************************************************************************************
226.	The code is designed and produced by MDY Science and Education Co., Ltd, which has the entire ownership. It is only for personal learning, which cannot be used for commercial or profit-making purposes without permission.
227.	
228.	    MDY's Mission: Develop Chip Talents and Realize National Chip Dream.
229.	
230.	    We sincerely hope that our students can learn the real IC / FPGA code through our standard and rigorous code.
231.	
232.	    For more FPGA learning materials, please visit the Forum: http://fpgabbs.com/ and official website: http://old.mdy-edu.com/index.html 
233.	
234.	    *************************************************************************************/
235.	
236.	
237.	module  traf_light2(
238.	    clk         ,
239.	    rst_n       ,
240.	    led_east    ,
241.	    led_south   ,
242.	    led_west    ,
243.	    led_north   
244.	    );
245.	
246.	
247.	
248.	parameter   COUNT_TIME      =   26'd5000_0000;
249.	parameter   CYCLE_TIME      =   5'd30        ;
250.	parameter   COUNT_WID       =   26           ;
251.	parameter   SEC_WID         =   5            ;
252.	parameter   LED_NUM         =   3            ;
253.	parameter   STA_W           =   2            ;
254.	
255.	parameter   STA_G           =   2'd1         ;
256.	parameter   STA_Y           =   2'd2         ;
257.	parameter   STA_R           =   2'd3         ;
258.	parameter   GREEN           =   3'b110       ;
259.	parameter   YELLOW          =   3'b101       ;
260.	parameter   RED             =   3'b011       ;
261.	
262.	
263.	input                   clk                 ;
264.	input                   rst_n               ;
265.	output  [LED_NUM-1:0]   led_east            ;
266.	output  [LED_NUM-1:0]   led_south           ;
267.	output  [LED_NUM-1:0]   led_west            ;
268.	output  [LED_NUM-1:0]   led_north           ;
269.	
270.	reg     [LED_NUM-1:0]   led_east            ;
271.	reg     [LED_NUM-1:0]   led_south           ;
272.	reg     [LED_NUM-1:0]   led_west            ;
273.	reg     [LED_NUM-1:0]   led_north           ;
274.	
275.	reg     [COUNT_WID-1:0] counter             ;
276.	wire                    add_counter         ;
277.	wire                    end_counter         ;
278.	reg     [SEC_WID-1:0]   second              ;
279.	wire                    add_second          ;
280.	wire                    end_second          ;
281.	
282.	reg     [STA_W-1:0]     ew_state_c            ;
283.	reg     [STA_W-1:0]     ew_state_n            ;
284.	wire                    idle2sta_g_start_ew   ;
285.	wire                    sta_g2sta_y_start_ew  ;
286.	wire                    sta_y2sta_r_start_ew  ;
287.	wire                    sta_r2sta_g_start_ew  ;
288.	
289.	reg     [STA_W-1:0]     sn_state_c            ;
290.	reg     [STA_W-1:0]     sn_state_n            ;
291.	wire                    idle2sta_r_start_sn   ;
292.	wire                    sta_r2sta_g_start_sn  ;
293.	wire                    sta_g2sta_y_start_sn  ;
294.	wire                    sta_y2sta_r_start_sn  ;
295.	
296.	
297.	always @(posedge clk or negedge rst_n) begin 
298.	    if (rst_n==0) begin
299.	        counter <= 0; 
300.	    end
301.	    else if(add_counter) begin
302.	        if(end_counter)
303.	            counter <= 0; 
304.	        else
305.	            counter <= counter+1 ;
306.	   end
307.	end
308.	assign add_counter = 1;
309.	assign end_counter = add_counter  && counter == COUNT_TIME-1 ;
310.	
311.	
312.	always @(posedge clk or negedge rst_n) begin 
313.	    if (rst_n==0) begin
314.	        second <= 0; 
315.	    end
316.	    else if(add_second) begin
317.	        if(end_second)
318.	            second <= 0; 
319.	        else
320.	            second <= second+1 ;
321.	   end
322.	end
323.	assign add_second = end_counter;
324.	assign end_second = add_second  && second == CYCLE_TIME-1 ;
325.	
326.	
327.	always @(posedge clk or negedge rst_n) begin 
328.	    if (rst_n==0) begin
329.	        ew_state_c <= STA_G ;
330.	    end
331.	    else begin
332.	        ew_state_c <= ew_state_n;
333.	   end
334.	end
335.	
336.	always @(*) begin 
337.	    case(ew_state_c)  
338.	        STA_G :begin
339.	            if(sta_g2sta_y_start_ew) 
340.	                ew_state_n = STA_Y ;
341.	            else 
342.	                ew_state_n = ew_state_c ;
343.	        end
344.	        STA_Y :begin
345.	            if(sta_y2sta_r_start_ew) 
346.	                ew_state_n = STA_R ;
347.	            else 
348.	                ew_state_n = ew_state_c ;
349.	        end
350.	        STA_R :begin
351.	            if(sta_r2sta_g_start_ew) 
352.	                ew_state_n = STA_G ;
353.	            else 
354.	                ew_state_n = ew_state_c ;
355.	        end
356.	        default : ew_state_n = STA_G ;
357.	    endcase
358.	end
359.	
360.	assign sta_g2sta_y_start_ew = ew_state_c==STA_G && add_second  && second == 10-1;
361.	assign sta_y2sta_r_start_ew = ew_state_c==STA_Y && add_second  && second == 15-1;
362.	assign sta_r2sta_g_start_ew = ew_state_c==STA_R && add_second  && second == 30-1;
363.	
364.	always  @(posedge clk or negedge rst_n)begin
365.	    if(rst_n==1'b0)begin
366.	        led_east<=GREEN; 
367.	    end
368.	    else if(ew_state_c==STA_G)begin
369.	        led_east<=GREEN;
370.	    end
371.	    else if(ew_state_c==STA_Y)begin
372.	        led_east<=YELLOW;
373.	    end
374.	    else if(ew_state_c==STA_R)begin
375.	        led_east<=RED;
376.	    end
377.	    else begin
378.	        led_east<=GREEN;
379.	    end
380.	end
381.	
382.	always  @(posedge clk or negedge rst_n)begin
383.	    if(rst_n==1'b0)begin
384.	        led_west<=GREEN; 
385.	    end
386.	    else if(ew_state_c==STA_G)begin
387.	        led_west<=GREEN;
388.	    end
389.	    else if(ew_state_c==STA_Y)begin
390.	        led_west<=YELLOW;
391.	    end
392.	    else if(ew_state_c==STA_R)begin
393.	        led_west<=RED;
394.	    end
395.	    else begin
396.	        led_west<=GREEN;
397.	    end
398.	end
399.	
400.	
401.	
402.	always @(posedge clk or negedge rst_n) begin 
403.	    if (rst_n==0) begin
404.	        sn_state_c <= STA_R ;
405.	    end
406.	    else begin
407.	        sn_state_c <= sn_state_n;
408.	   end
409.	end
410.	
411.	always @(*) begin 
412.	    case(sn_state_c)  
413.	        STA_R :begin
414.	            if(sta_r2sta_g_start_sn) 
415.	                sn_state_n = STA_G ;
416.	            else 
417.	                sn_state_n = sn_state_c ;
418.	        end
419.	        STA_G :begin
420.	            if(sta_g2sta_y_start_sn) 
421.	                sn_state_n = STA_Y ;
422.	            else 
423.	                sn_state_n = sn_state_c ;
424.	        end
425.	        STA_Y :begin
426.	            if(sta_y2sta_r_start_sn) 
427.	                sn_state_n = STA_R ;
428.	            else 
429.	                sn_state_n = sn_state_c ;
430.	        end
431.	        default : sn_state_n = STA_R ;
432.	    endcase
433.	end
434.	
435.	assign sta_r2sta_g_start_sn = sn_state_c==STA_R && add_second  && second == 15-1;
436.	assign sta_g2sta_y_start_sn = sn_state_c==STA_G && add_second  && second == 25-1;
437.	assign sta_y2sta_r_start_sn = sn_state_c==STA_Y && add_second  && second == 30-1;
438.	
439.	always  @(posedge clk or negedge rst_n)begin
440.	    if(rst_n==1'b0)begin
441.	        led_south<=RED; 
442.	    end
443.	    else if(sn_state_c==STA_G)begin
444.	        led_south<=GREEN;
445.	    end
446.	    else if(sn_state_c==STA_Y)begin
447.	        led_south<=YELLOW;
448.	    end
449.	    else if(sn_state_c==STA_R)begin
450.	        led_south<=RED;
451.	    end
452.	    else begin
453.	        led_south<=GREEN;     
454.	    end
455.	end
456.	
457.	always  @(posedge clk or negedge rst_n)begin
458.	    if(rst_n==1'b0)begin
459.	        led_north<=RED; 
460.	    end
461.	    else if(sn_state_c==STA_G)begin
462.	        led_north<=GREEN;
463.	    end
464.	    else if(sn_state_c==STA_Y)begin
465.	        led_north<=YELLOW;
466.	    end
467.	    else if(sn_state_c==STA_R)begin
468.	        led_north<=RED;
469.	    end
470.	    else begin
471.	        led_north<=GREEN;   
472.	    end
473.	end
474.	
475.	endmodule
476.	




1.2 效果和总结


点拨板:


1. 复位,东西绿灯亮,南北红灯亮

「每周FPGA案例」状态机实现的LED交通灯2

2. 10秒后,东西黄灯亮,南北还是红灯亮

「每周FPGA案例」状态机实现的LED交通灯2

3. 15秒后,东西红灯亮,南北绿灯亮

「每周FPGA案例」状态机实现的LED交通灯2

4. 20秒后。东西还是红灯亮,南北黄灯亮

「每周FPGA案例」状态机实现的LED交通灯2

5. 30秒后,东西绿灯亮,南北红灯亮

「每周FPGA案例」状态机实现的LED交通灯2

Mp801:


1. 复位,东西绿灯亮,南北红灯亮

「每周FPGA案例」状态机实现的LED交通灯2

2. 10秒后,东西黄灯亮,南北还是红灯亮

「每周FPGA案例」状态机实现的LED交通灯2

3. 15秒后,东西红灯亮,南北绿灯亮

「每周FPGA案例」状态机实现的LED交通灯2

4. 20秒后。东西还是红灯亮,南北黄灯亮

「每周FPGA案例」状态机实现的LED交通灯2

5. 30秒后,东西绿灯亮,南北红灯亮

「每周FPGA案例」状态机实现的LED交通灯2


实验箱:


1. 复位,东西绿灯亮,南北红灯亮

「每周FPGA案例」状态机实现的LED交通灯2

2. 10秒后,东西黄灯亮,南北还是红灯亮

「每周FPGA案例」状态机实现的LED交通灯2

3. 15秒后,东西红灯亮,南北绿灯亮

「每周FPGA案例」状态机实现的LED交通灯2

4. 20秒后。东西还是红灯亮,南北黄灯亮

「每周FPGA案例」状态机实现的LED交通灯2

5. 30秒后,东西绿灯亮,南北红灯亮

「每周FPGA案例」状态机实现的LED交通灯2

观看上面的现象,可以发现,各项功能正常:开发板上有红黄绿三色 LED 灯各四个,在东西南北方向各有一组。参考交通灯的情况,即每个方向都是绿灯亮 10 秒,然后黄灯亮 5 秒,然后红灯亮 15 秒。绿灯按照东西和南北的顺序依次亮。成功完成设计目标。

温馨提示:明德扬2023推出了全新课程——逻辑设计基本功修炼课,降低学习FPGA门槛的同时,增加了学习的趣味性,并组织了考试赢积分活动

http://www.mdy-edu.com/ffkc/415.html

(点击→了解课程详情☝)感兴趣请联系易老师:13112063618(微信同步)



本文TAG:

Copyright © 2012-2023 版权所有:深圳明德扬科技教育有限公司