呼吸灯和人的呼吸频率一样led灯光熄灭的表现。我们通常看到的基本上是瞬间的开启和关闭。当然,它也有一定的开启和关闭时间,但我们无法用肉眼区分。因此,我们实验的主要困难在于使我们led慢慢变亮,变亮后慢慢变灭。我们看到这一点的第一个想法是控制电流的大小,但在Quartus它似乎不容易实现,所以我们可以改变我们的想法。
这里引入了一个新名词,占空比(DutyCycleorDutyRatio),空比控制又称电控脉宽调制技术。它是通过电子控制单元调添加到工作执行器上的一定频率的电压信号的脉冲宽度,即空比控制,以实现元器件工作条件的准确和连续控制。一般来说,它是指电路连接时间占整个电路工作周期的百分比。例如,如果一个电路在一个工作周期中连接了一半,则其空间占50%。工作元件上的信号电压为5V,则实际的工作电压平均值或电压有效值就是2.5V。假设该元件为电子阀,当电路完全连接时,阀门完全打开;当空间占50%时,阀门状态为半开。同样,当占空比设置为20%时,阀门的开度明显应为20%。这样,阀门可以在0%(全闭)到100%(全开)范围内任意调节。
在此次实验中,我们就可以采用这个原理,假设刚开始时占空比为1%,慢慢的占空比为2%、3%、4%……98%,99%,100%。这就是LED在灯亮的过程中,我们可以让占空比为1%LED灯亮,剩下的让LED灭,慢慢占空比越来越大,亮部也越来越多,这是一个从灭到亮的过程。
相反,我们假设一开始占100%,慢慢占99%、98%、97%……2%,1%,0%。LED在灯灭的过程中,我们可以让占空比达到99%LED灯灭,剩下的让LED亮,慢慢占空比越来越小,灭部也越来越多,这是一个从亮到灭的过程。
这里我们用两个按钮控制led呼吸灯的时间,按键1,让它在一秒钟内从暗变亮,然后从一秒钟内从亮变暗;按键2,让它在三秒钟内从暗变亮,再从三秒钟内从亮变暗。
用三个计数器单独计数,思路是把1s拆分为1000ms,再将1ms拆分为1000us;第一个计数器cnt_us用来实现对us第二个计数器cnt_ms实现对ms计数,第三个计数器cnt_s实现s计数,具体过程可见下面的代码。
4.1 顶层模块
module led_huxi ( input clk, input rst_n, input [1:0] key_in, output [3:0] led_out ); wire [1:0] key_out ; key u_key1( .clk (clk), .rst_n (rst_n), .key_in (key_in[0]), .key_out (key_out[0]) ); key u_key2( .clk (clk), .rst_n (rst_n), .key_in (key_in[1]), .key_out(key_out[1]) ); led_control u_led_control( .clk (clk ), .rst_n (rst_n ), .key_in (key_out), .led (led_out) ); endmodule
4.2 按钮抖动模块,在前面的文章中,不具体介绍。
module key( input clk, input rst_n, input key_in, output reg key_out ); parameter TIME_DELAY = 1_000_000; reg [19:0] cnt ; wire add_cnt; wire end_cnt; wire nedge ; reg cnt_flag ; reg key_r0 ; reg key_r1 ; reg key_r2 ; always @(posedge clk or negedge rst_n) begin if(!rst_n) begin key_r0 <= 1'd1; key_r1 <= 1'd1; key_r2 <= 1'd1; end else begin key_r0 <= key_in; key_r1 <= key_r0; key_r2 <= key_r1; end end assign nedge = ~key_r1 && key_r2; always @(posedge clk or negedge rst_n) begin if(!rst_n)begin cnt_flag <= 1'b0; end else if (nedge)begin cnt_flag <= 1'b1; end else if (end_cnt)begin cnt_flag <= 1'b0; end else begin cnt_flag <= cnt_flag; end end always @(posedge clk or negedge rst_n) begin if(!rst_n)begin cnt <= 'd0; end else if (add_cnt)begin if (end_cnt) begin cnt <= 'd0; end else begin cnt <= cnt 1'b1; end end end assign add_cnt = cnt_flag; assign end_cnt = add_cnt && cnt == TIME_DELAY - 1; always @(posedge clk or negedge rst_n) begin if(!rst_n)begin key_out <= 1'b0; end else if(end_cnt)begin key_out <= ~key_r2; end else begin key_out <= 1'b0; end end endmodule
4.3 占空比的核心代码和led灯的控制模块
module led_control ( input clk, input rst_n, input [1:0] key_in, output reg [3:0 ] led ); reg [7:0] cnt_us ; wire add_cnt_us; wire end_cnt_us; reg [9:0] cnt_ms ; wire add_cnt_ms; wire end_cnt_ms; reg [9:0] cnt_s ; wire add_cnt_s; wire end_cnt_s; reg flag; reg [7:0] num ; parameter cnt_us_max = 8'd50; parameter cnt_us_max_1 = 8'd150; parameter cnt_ms_max = 10'd999; parameter cnt_s_max = 10'd999; //1us always@( posedge clk or negedge rst_n) begin if(!rst_n)begin cnt_us <= 8'd0; end else if (add_cnt_us) begin if(end_cnt_us)begin cnt_us <= 8'd0; end else begin cnt_us <= cnt_us 1'b1; end end end assign add_cnt_us = 1'b1; assign end_cnt_us = add_cnt_us && cnt_us == num -1; //1ms always@( posedge clk or negedge rst_n) begin if(!rst_n) begin cnt_ms <= 10'd0; end else if (add_cnt_ms)begin if(end_cnt_ms)begin cnt_ms <= 10'd0; end else begin cnt_ms <= cnt_ms 1'b1; end en
end
assign add_cnt_ms = end_cnt_us;
assign end_cnt_ms = add_cnt_ms && cnt_ms == cnt_ms_max ;
// 1s
always@( posedge clk or negedge rst_n) begin
if(!rst_n) begin
cnt_s <= 10'd0;
end
else if (add_cnt_s)begin
if(end_cnt_s)begin
cnt_s <= 10'd0;
end
else begin
cnt_s <= cnt_s + 1'b1;
end
end
end
assign add_cnt_s = end_cnt_ms;
assign end_cnt_s = add_cnt_s && cnt_s == cnt_s_max ;
//flag标志
always @(posedge clk or negedge rst_n)begin
if(!rst_n) begin
flag <= 1'b0;
end
else if (cnt_s== cnt_s_max && cnt_us == num-1 && cnt_ms == cnt_ms_max ) begin
flag <= ~flag;
end
else begin
flag <= flag;
end
end
//led
always@( posedge clk or negedge rst_n) begin
if(!rst_n) begin
led <= 4'b1111;
end
else if ((flag == 1'b1 && cnt_ms < cnt_s)||(flag == 1'b0 && cnt_s < cnt_ms))
begin
led <= 4'b1111;
end
else begin
led <= 4'b0000;
end
end
//按键
always@( posedge clk or negedge rst_n) begin
if (!rst_n)begin
num <= 8'd0;
end
else if (key_in[0]==1&&key_in[1]==0) begin
num <= cnt_us_max ;
end
else if (key_in[1]==1&&key_in[0]==0) begin
num <= cnt_us_max_1 ;
end
end
endmodule
4.4 视频演示
呼吸灯