設計規劃
呼吸燈的效果是LED燈在一段時間內從完全熄滅的狀態逐漸變到最亮,再在同樣的時間段內逐漸達到完全熄滅的狀態。這里我們需要實現1s內實現從滅到亮,1s內從亮到滅。
LED的明亮有兩種方式,第一種是在安全范圍內給LED燈不同的供電電壓可以控制明滅;第二種是通過控制PWM的 占空比 ,同一時間段內供給LED燈一個脈沖信號的低電平持續時間越長,LED燈越亮。我們取n個相同的時間段,讓低電平的持續時間按照相等的時間間隔逐漸增多,led燈就會越來越亮了。
首先我們將1s分為1000個時間段,每段1ms。再將1ms分為1000個時間小段,每段1us。第一個1ms內亮0us(滅),并在第二個1ms內亮1us,...,在第1000個1ms內亮999us。劃分的等級越多,看上去效果越好,但是人眼分辨率有限,大于這個分辨率就看起來幾乎沒有差異。
我們至少需要三個計數器,用來計時1s,1ms,1us。cnt_1us需要從0計數到49,不復位就計數,計滿就清零。cnt_1ms完全沒必要重新產生,每當cnt_1ms計數到999且cnt_1us計數到49,cnt_1ms就清零。cnt_1s同理在cnt_1ms計數到999且cnt_1us計數到49時就清零。
led_out要在不同時間段低電平持續時長慢慢增加,需要一個小技巧。觀察上圖,LED為低電平時,cnt_1s是0時,cnt_1ms是1-999;cnt_1s是1時,cnt_1ms是2-999...
LED燈從亮到滅是相反的過程,LED燈為高電平時,cnt_1s>cnt_1ms。
區分從滅到亮和從亮到滅,可以使用一個電平標志信號(使能)cnt_1s_en。cnt_1s_en為低電平時實現呼吸燈從滅到亮的過程,cnt_1s_en為高的時候實現呼吸燈從亮到滅的過程,cnt_1s清零時cnt_1s_en取反。
編寫代碼
module breath_led
#(
parameter CNT_1US_MAX = 6'd49 ,
parameter CNT_1MS_MAX = 10'd999 ,
parameter CNT_1S_MAX = 10'd999
)
(
input wire sys_clk ,
input wire sys_rst_n ,
output reg led_out
);
//reg define
reg [5:0] cnt_1us ;
reg [9:0] cnt_1ms ;
reg [9:0] cnt_1s ;
reg cnt_1s_en ;
//cnt_1us:1us計數器
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_1us <= 6'b0;
else if(cnt_1us == CNT_1US_MAX)
cnt_1us <= 6'b0;
else
cnt_1us <= cnt_1us + 1'b1;
//cnt_1ms:1ms計數器
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_1ms <= 10'b0;
else if(cnt_1ms == CNT_1MS_MAX && cnt_1us == CNT_1US_MAX)
cnt_1ms <= 10'b0;
else if(cnt_1us == CNT_1US_MAX)
cnt_1ms <= cnt_1ms + 1'b1;
//cnt_1s:1s計數器
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_1s <= 10'b0;
else if(cnt_1s == CNT_1S_MAX && cnt_1ms == CNT_1MS_MAX
&& cnt_1us == CNT_1US_MAX)
cnt_1s <= 10'b0;
else if(cnt_1ms == CNT_1MS_MAX && cnt_1us == CNT_1US_MAX)
cnt_1s <= cnt_1s + 1'b1;
//cnt_1s_en:1s計數器標志信號
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_1s_en <= 1'b0;
else if(cnt_1s == CNT_1S_MAX && cnt_1ms == CNT_1MS_MAX
&& cnt_1us == CNT_1US_MAX)
cnt_1s_en <= ~cnt_1s_en;
//led_out:輸出信號連接到外部的led燈
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
led_out <= 1'b0;
else if((cnt_1s_en == 1'b1 && cnt_1ms < cnt_1s)||
(cnt_1s_en == 1'b0 && cnt_1ms > cnt_1s))
led_out <= 1'b0;
else
led_out <= 1'b1;
endmodule