呼吸灯:
呼吸灯是一种特殊的灯光效果,它可以模拟呼吸的效果,即灯光逐渐由暗变亮再由亮变暗,循环往复。这种效果给人一种柔和、舒缓的感觉,常被应用在装饰、照明和显示等领域。
PWM呼吸灯设计:
在数字电路设计中,通常使用脉宽调制(PWM)技术来实现呼吸灯效果。PWM通过改变信号的高电平时间比例来控制输出的亮度。实现呼吸灯效果的关键是改变PWM的占空比,也就是高电平时间与周期时间的比例。
使用开发板上的四个led灯实现1s间隔的呼吸灯。
代码:
/*
2023.7.13
呼吸灯设计pwm_led
实现1s间隔的呼吸灯
*/
module breath_led(
input wire clk ,
input wire rst_n ,
output reg[3:0] led
);
parameter TIME_US = 6'd49;//50*20ns=1us
parameter TIME_MS = 10'd999;//1us*1000=1ms
parameter TIME_S = 10'd999;//1ms*1000=1s
reg [5:0] cnt_us;
reg [9:0] cnt_ms;
reg [9:0] cnt_s;
wire add_cnt_us;//us计数器开始计数标志
wire end_cnt_us;//us计数器结束计数标志
wire add_cnt_ms;//ms计数器开始计数标志
wire end_cnt_ms;//ms计数器结束计数标志
wire add_cnt_s;
wire end_cnt_s;
reg flag;//闪烁标志
//1us计时器
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
cnt_us <= 6'd0;
end
else if (add_cnt_us) begin//add_cnt_us 为 1 时开始计数
if(end_cnt_us)begin//end_cnt_us 为 1 时为计满,重新置零
cnt_us <= 6'd0;
end
else begin
cnt_us <= cnt_us +1'd1;
end
end
else begin
cnt_us <= cnt_us;
end
end
assign add_cnt_us = 1'b1;
assign end_cnt_us = add_cnt_us && cnt_us == TIME_US;
//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'd1;
end
end
else begin
cnt_ms <= cnt_ms;
end
end
assign add_cnt_ms = end_cnt_us;
assign end_cnt_ms = add_cnt_ms && cnt_ms == TIME_MS;
//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'd1;
end
end
else begin
cnt_s <= cnt_s;
end
end
assign add_cnt_s = end_cnt_ms;
assign end_cnt_s = add_cnt_s && cnt_s == TIME_S;
//flag值判断
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
flag <= 1'b0;
end
else if(end_cnt_s) begin//1s取反
flag <= ~flag;
end
else begin
flag <= flag;
end
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
led <= 4'b0000;
end
else begin
if(flag == 1'b1)begin//电亮
led <= (cnt_s > cnt_ms) ? 4'b1111 : 4'b0000;
end
else begin
led <= (cnt_s > cnt_ms) ? 4'b0000 : 4'b1111;
end
end
end
endmodule
测试文件:
`timescale 1ns/1ns
module breath_led_tb();
reg clk;
reg rst_n;
wire [3:0] led;
parameter CYCLE = 20;
parameter TIME_US = 5;
parameter TIME_MS = 10;
parameter TIME_S = 10;
always #(CYCLE/2) clk = ~clk;
initial begin
clk = 1'b0;
rst_n = 1'b0;//开始复位
#(CYCLE);
rst_n = 1'b1;//结束复位
#((TIME_US + 1)*(TIME_MS + 1)*(TIME_S + 1)*CYCLE*2);
$stop;
end
breath_led #(
.TIME_US (TIME_US),
.TIME_MS (TIME_MS),
.TIME_S (TIME_S)
)u_breath_led(
.clk (clk),
.rst_n (rst_n),
.led (led)
);
endmodule
我们通过modelsim仿真结果如下:
其中我们能清晰看出在flag值为0的时候,高电平时间比例越来越小,说明灯在逐渐熄灭,在flag值为1的时候,高电平时间比列越来越大,说明灯在逐渐电亮。
结果展示: