1.1 總體設計
1.1.1 概述
發光二極管簡稱為LED,是一種常用的發光器件,通過電子與空穴復合釋放能量發光,它可以高效的將電能轉化為光能,在現代社會具有廣泛的用途,如照明、平板顯示、醫療器件等??赏ㄟ^高低電平的變化來控制LED燈的明滅狀態,當輸出信號為低電平時,LED燈亮,反之,當輸出信號為高電平時,LED燈滅。
1.1.2 設計目標
實現開發板上東西南北 4 個方向,每個方向上的 3 個 LED 燈按照“綠燈--黃燈--紅燈--綠燈--黃燈......”依次循環變化。變化的速度不同,東面的間隔時間為 1 秒;西面的間隔時間為 2 秒;南面的間隔時間為 3 秒;北面的間隔時間為 4 秒。
具體要求:
1、每個方向的燈分開獨立設計。
2、首先設計東向的燈:設計一個計時 1 秒的計數器,用來計算燈的狀態變化的時間間隔。
3、如果計時 1 秒到了,把黃燈點亮;再過 1 秒把紅燈點亮;再過 1 秒,把綠燈點亮......
依次循環。
4、設計西方向的燈:設計一個計時 2 秒的計數器,其他的類似。
5、其它兩個方向的設計類似。
1.1.3 信號列表

1.1.4 設計思路
根據題目功能要求,東西南北四個方向LED燈顏色變換的速度都不同。因為在數字電路中的延時都是通過計數器實現的,計數器*時鐘周期=延時時間。本模塊中,由于輸入時鐘是50MHz,時鐘周期為20ns,功能要求每1秒變化一次。我們通過counter來表示延時,當其值為1s/20ns=5000_0000時,表示1秒時間到。
本工程架構由四個計數器組成:

東方向計數器e_counter:該計數器用于計算東向1s的時鐘個數,加一條件為1,表示一直計數;數到5000_0000下,則表示數到1秒了。
西方向計數器w_counter:該計數器用于計算西向2s的時鐘個數,加一條件為1,表示一直計數;數到2*5000_0000下,則表示數到2秒了。
南方向計數器s_counter:該計數器用于計算南向3s的時鐘個數,加一條件為1,表示一直計數;數到3*5000_0000下,則表示數到3秒了。
北方向計數器n_counter:該計數器用于計算北向4s的時鐘個數,加一條件為1,表示一直計數;數到4*5000_0000下,則表示數到4秒了。
下面是東西南北四個方向的秒計數器的代碼。
parameter COUNT_1S = 26'd5000_0000; parameter COUNT_WID = 28;
reg [COUNT_WID-1:0] e_counter; reg [COUNT_WID-1:0] s_counter; reg [COUNT_WID-1:0] w_counter; reg [COUNT_WID-1:0] n_counter;
wire add_e_counter; wire end_e_counter; wire add_w_counter; wire end_w_counter; wire add_s_counter; wire end_s_counter; wire add_n_counter; wire end_n_counter; |
always @(posedge clk or negedge rst_n) begin if (rst_n==0) begin e_counter <= 0; end else if(add_e_counter) begin if(end_e_counter) e_counter <= 0; else e_counter <= e_counter+1 ; end end assign add_e_counter = 1; assign end_e_counter = add_e_counter && e_counter == COUNT_1S-1 ;
always @(posedge clk or negedge rst_n) begin if (rst_n==0) begin w_counter <= 0; end else if(add_w_counter) begin if(end_w_counter) w_counter <= 0; else w_counter <= w_counter+1 ; end end assign add_w_counter = 1; assign end_w_counter = add_w_counter && w_counter == 2*COUNT_1S-1 ;
always @(posedge clk or negedge rst_n) begin if (rst_n==0) begin s_counter <= 0; end else if(add_s_counter) begin if(end_s_counter) s_counter <= 0; else s_counter <= s_counter+1 ; end end assign add_s_counter = 1; assign end_s_counter = add_s_counter && s_counter == 3*COUNT_1S-1 ;
always @(posedge clk or negedge rst_n) begin if (rst_n==0) begin n_counter <= 0; end else if(add_n_counter) begin if(end_n_counter) n_counter <= 0; else n_counter <= n_counter+1 ; end end assign add_n_counter = 1; assign end_n_counter = add_n_counter && n_counter == 4*COUNT_1S-1 ; |
LED燈信號的變化,根據功能要求,東面的間隔時間為 1 秒;西面的間隔時間為 2 秒;南面2的間隔時間為 3 秒;北面的間隔時間為 4 秒。計數時間到時變化;時間沒到,則不變化。每一時刻每個方向只有一個燈亮,并且亮燈的顏色順序按照“綠燈--黃燈--紅燈--綠燈--黃燈.....”依次循環變化。
東西南北四個方向的各有三盞不同顏色的LED燈,每個方向的三個LED燈都由3 比特信號控制,最高位為紅燈,最低位為綠燈,并且低電平時LED燈亮。led_east表示東面三個LED燈,led_west表示西面三個LED燈,led_south表示南面三個LED燈,led_north表示北面三個LED燈。
三色LED燈的循環變換控制可以通過拼接的方法使數據循環左移來實現。
以led_east的變化為例,上電后,led_east[2:0]=3’b110;然后每隔1秒,依次循環變化:101,011,110。即end_e_counter(每隔1秒)時,led_east[2:0]數值循環左移,其他時候不變。
led_west、led_south、led_north也是同理,即:
上電后,led_west[2:0]=3’b110;然后每隔2秒,依次循環變化:101,011,110。即end_w_counter(每隔2秒)時,led_west[2:0]數值循環左移,其他時候不變。
上電后,led_south[2:0]=3’b110;然后每隔3秒,依次循環變化:101,011,110。即end_s_counter(每隔3秒)時,led_south[2:0]數值循環左移,其他時候不變。
上電后,led_north[2:0]=3’b110;然后每隔4秒,依次循環變化:101,011,110。即end_n_counter(每隔4秒)時,led_north[2:0]數值循環左移,其他時候不變。
下面是個東西南北四個方向的LED燈亮燈控制代碼。
parameter LED_LEN = 3;
output [LED_LEN-1:0] led_east; output [LED_LEN-1:0] led_south; output [LED_LEN-1:0] led_west; output [LED_LEN-1:0] led_north;
reg [LED_LEN-1:0] led_east; reg [LED_LEN-1:0] led_south; reg [LED_LEN-1:0] led_west; reg [LED_LEN-1:0] led_north; |
always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin led_east<={{(LED_LEN-1){1'b1}},1'b0}; end else if(end_e_counter)begin led_east<={led_east[LED_LEN-2:0],led_east[LED_LEN-1]}; end else begin led_east<=led_east; end end
always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin led_west<={{(LED_LEN-1){1'b1}},1'b0}; end else if(end_w_counter)begin led_west<={led_west[LED_LEN-2:0],led_west[LED_LEN-1]}; end else begin led_west<=led_west; end end
always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin led_south<={{(LED_LEN-1){1'b1}},1'b0}; end else if(end_s_counter)begin led_south<={led_south[LED_LEN-2:0],led_south[LED_LEN-1]}; end else begin led_south<=led_south; end end
always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin led_north<={{(LED_LEN-1){1'b1}},1'b0}; end else if(end_n_counter)begin led_north<={led_north[LED_LEN-2:0],led_north[LED_LEN-1]}; end else begin led_north<=led_north; end end |
1.1.5 參考設計代碼
module traf_light1( clk , rst_n , led_east , led_south , led_west , led_north );
parameter LED_LEN = 3; parameter COUNT_1S = 26'd5000_0000; parameter COUNT_WID = 28;
input clk ; input rst_n ; output [LED_LEN-1:0] led_east ; output [LED_LEN-1:0] led_south; output [LED_LEN-1:0] led_west ; output [LED_LEN-1:0] led_north;
reg [LED_LEN-1:0] led_east ; reg [LED_LEN-1:0] led_south; reg [LED_LEN-1:0] led_west ; reg [LED_LEN-1:0] led_north;
reg [COUNT_WID-1:0] e_counter; reg [COUNT_WID-1:0] s_counter; reg [COUNT_WID-1:0] w_counter; reg [COUNT_WID-1:0] n_counter;
wire add_e_counter; wire end_e_counter; wire add_w_counter; wire end_w_counter; wire add_s_counter; wire end_s_counter; wire add_n_counter; wire end_n_counter;
always @(posedge clk or negedge rst_n) begin if (rst_n==0) begin e_counter <= 0; end else if(add_e_counter) begin if(end_e_counter) e_counter <= 0; else e_counter <= e_counter+1 ; end end assign add_e_counter = 1; assign end_e_counter = add_e_counter && e_counter == COUNT_1S-1 ;
always @(posedge clk or negedge rst_n) begin if (rst_n==0) begin w_counter <= 0; end else if(add_w_counter) begin if(end_w_counter) w_counter <= 0; else w_counter <= w_counter+1 ; end end assign add_w_counter = 1; assign end_w_counter = add_w_counter && w_counter == 2*COUNT_1S-1 ;
always @(posedge clk or negedge rst_n) begin if (rst_n==0) begin s_counter <= 0; end else if(add_s_counter) begin if(end_s_counter) s_counter <= 0; else s_counter <= s_counter+1 ; end end assign add_s_counter = 1; assign end_s_counter = add_s_counter && s_counter == 3*COUNT_1S-1 ;
always @(posedge clk or negedge rst_n) begin if (rst_n==0) begin n_counter <= 0; end else if(add_n_counter) begin if(end_n_counter) n_counter <= 0; else n_counter <= n_counter+1 ; end end assign add_n_counter = 1; assign end_n_counter = add_n_counter && n_counter == 4*COUNT_1S-1 ;
always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin led_east<={{(LED_LEN-1){1'b1}},1'b0}; end else if(end_e_counter)begin led_east<={led_east[LED_LEN-2:0],led_east[LED_LEN-1]}; end else begin led_east<=led_east; end end
always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin led_west<={{(LED_LEN-1){1'b1}},1'b0}; end else if(end_w_counter)begin led_west<={led_west[LED_LEN-2:0],led_west[LED_LEN-1]}; end else begin led_west<=led_west; end end
always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin led_south<={{(LED_LEN-1){1'b1}},1'b0}; end else if(end_s_counter)begin led_south<={led_south[LED_LEN-2:0],led_south[LED_LEN-1]}; end else begin led_south<=led_south; end end
always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin led_north<={{(LED_LEN-1){1'b1}},1'b0}; end else if(end_n_counter)begin led_north<={led_north[LED_LEN-2:0],led_north[LED_LEN-1]}; end else begin led_north<=led_north; end end
endmodule |
1.2 效果和總結
點撥板
1. 復位,東西南北四面都是綠燈

2. 時間經過1秒后,東面變為黃燈,其余三面還是綠燈

3. 時間經過2秒后,東面變為紅燈,西面變為黃燈,其余兩面不變

4. 時間經過3秒后,東面又變回綠燈,南面變為黃燈,西面還是黃燈,北面還是綠燈不變

5. 時間經過4秒后,東面循環變為黃燈,南面還是黃燈,西面變為紅燈,北面變為黃燈

Mp801
1. 復位,東西南北四面都是綠燈

2. 時間經過1秒后,東面變為黃燈,其余三面還是綠燈

3. 時間經過2秒后,東面變為紅燈,西面變為黃燈,其余兩面不變

4. 時間經過3秒后,東面又變回綠燈,南面變為黃燈,西面還是黃燈,北面還是綠燈不變

5. 時間經過4秒后,東面循環變為黃燈,南面還是黃燈,西面變為紅燈,北面變為黃燈

實驗箱
1. 復位,東西南北四面都是綠燈

2. 時間經過1秒后,東面變為黃燈,其余三面還是綠燈

3. 時間經過2秒后,東面變為紅燈,西面變為黃燈,其余兩面不變

4. 時間經過3秒后,東面又變回綠燈,南面變為黃燈,西面還是黃燈,北面還是綠燈不變

5. 時間經過4秒后,東面循環變為黃燈,南面還是黃燈,西面變為紅燈,北面變為黃燈

觀看上面的現象,可以發現,工程各項功能正常:開發板上東西南北 4 個方向,每個方向上的 3 個 LED 燈按照“綠燈--黃燈--紅燈--綠燈--黃燈......”依次循環變化,并且東西南北 4 個方向LED燈變化的速度不同,東面的間隔時間為 1 秒;西面的間隔時間為 2 秒;南面的間隔時間為 3 秒;北面的間隔時間為 4 秒,成功完成設計目標。
設計視頻教程、工程源代碼請移步明德揚論壇觀看下載。
感興趣的朋友也可以訪問明德揚論壇(http://www.FPGAbbs.cn/)進行FPGA相關工程設計學習,也歡迎大家在評論進行討論!