1. 程式人生 > 其它 >led閃爍(時序簡單分析)

led閃爍(時序簡單分析)

1.設計定義

  設計一個以200ms亮,200ms暗交替閃爍的led燈,並且有一個復位按鈕可以停止工作。

2.設計輸入

  2.1埠

    以固定週期交替閃爍說明由時鐘控制,需要一個時鐘控制埠clk,要求復位按鈕,則需要一個復位埠reset,輸出為led燈,則有一個輸出埠led。

  2.2變數

    每個開發板的時鐘頻率是固定的,本次用的開發板時鐘週期為20ns。而led閃爍的週期為400ms,我們需要每200ms讓led改變一次狀態,這時便需要一個計數的變數counter,當counter達到(200ms/20ns)-1時讓led取反便可實現目標。注意,counter不屬於埠,故不寫在led模組裡面。且counter是個比較大的數,應該先計算一下位寬,這裡用程式設計師計算器輸入十進位制數,便可自動轉換為二進位制,得到位寬。

 1 module led_flash(    //2輸入1輸出
 2     clk,
 3     reset,
 4     led    
 5 );
 6     input  clk;
 7     input  reset;
 8     output reg led;
 9    
10     reg [23:0]counter;      //定義計數器,在module內,led外
11     
12     always@( posedge clk or negedge reset ) begin  //時序模擬,clk上升沿觸發,reset下降沿觸發。滿足任一條件就進入always執行
13 if(reset == 1'd1 )begin            //復位端有效,計數置零 14 counter <= 0; 15 end 16 else if( counter == 9999999 ) begin     //計數到200ms,計數器置零 17 counter <= 0; 18 end 19 else 20 counter <= counter + 1'd1;       //計數 21 end
22 23 always@( posedge clk or negedge reset ) begin 24 if(reset == 1'd1 )begin            //復位端有效,led熄滅 25 led <= 0; 26 end 27 else if( counter == 9999999 ) begin    //led翻轉狀態 28 led <= !led; 29 end 30 end 31 32 33 34 endmodule

3.綜合

4.綜合後功能模擬

 1 `timescale 1ns/1ns
 2 
 3 module led_flash_tb();
 4 
 5     reg s_clk;
 6     reg s_reset;
 7     wire s_led;
 8     
 9     led_flash led_flash_sim(
10         .clk(s_clk),
11         .reset(s_reset),
12         .led(s_led)    
13     );
14     
15     initial s_clk = 1;         //模擬時鐘訊號
16     always #10 s_clk = !s_clk;    //每10ns時鐘便翻轉一次,模擬開發板的時鐘
17    
18     initial begin
19     s_reset = 1;            //模擬復位端有效,持續101ns
20     #101;
21     s_reset = 0;
22     #400000000;           //復位端無效,持續400ms
23     $stop;
24     end
25 
26 endmodule

 5.佈局佈線

6.時序模擬,效能分析

7.板級除錯,設定i/o口,std,pin,下載到板子上。

  • 注意

1.在設計模組中,output reg xx可以,但input reg xx不可以。刪了reg,否則報錯。

2.一般只有埠放在你定義的模組部件裡,其他變數放在模組外,module內。如果變數不是簡單的0和1,則要定義它的位寬,用程式設計師計算器轉為2進位制即可快速寫出。

3.計算中+1最好寫出 + 1'd1(或其他進位制的1)比較規範。

4.有括號和賦值等語句,加個空格比較美觀。

5.時序電路最好用非阻塞賦值 <=。

6.模擬模擬時時鐘要翻轉很多次,不能再寫成之前的:

 s_a=0; s_b=0; s_sel=0;
#100;
 s_a=0; s_b=1; s_sel=0;
#100;
 s_a=1; s_b=0; s_sel=0;

要寫99999次不現實。因為只有兩個狀態在翻轉且週期固定,直接寫成:

initial s_clk = 1;         //模擬時鐘訊號
always #10 s_clk = !s_clk;    //每10ns時鐘便翻轉一次,模擬開發板的時鐘

7.當一個判斷條件語句(或其他語句)接著有多個操作時,用begin和end括起來才不會報錯。

8.學習復位訊號的模擬

initial begin
s_reset = 1;            //模擬復位端有效,持續101ns
 #101;
 s_reset = 0;
 #400000000;           //復位端無效,持續400ms
 $stop;

9.由於fpga是並行執行,而非按順序從上往下執行程式碼,故可以把多個操作分成幾個always進行,這樣有利於軟體綜合成較為簡單的電路,也方便我們修改程式碼。如下:

    always@( posedge clk or negedge reset ) begin
        if(reset == 1'd1 )begin
            counter <= 0;
            end
        else if( counter == 9999999 ) begin
            counter <= 0;
            end
        else
            counter <= counter + 1'd1;  
    end            

   always@( posedge clk or negedge reset ) begin
        if(reset == 1'd1 )begin
            led <= 0;
            end
        else if( counter == 9999999 ) begin
            led <= !led;
            end 
    end                 
    always@( posedge clk or negedge reset ) begin
        if(reset == 1'd1 )begin
            counter <= 0;
       led<=0;
end else if( counter == 9999999 ) begin counter <= 0;
       led<=!led;
end else counter <= counter + 1'd1; end

兩者等價,但第一種更好。

10.看時序模擬的時候可以進行標記,create market,以便觀察時間間隔。