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,以便觀察時間間隔。