Breathing light:
Breathing light is a special lighting effect, which can simulate the effect of breathing, that is, the light gradually changes from dark to bright and then from bright to dark, and the cycle goes on and on. This effect gives people a soft, soothing feeling and is often used in decoration, lighting and display and other fields.
PWM breathing light design:
In digital circuit design, pulse width modulation (PWM) technology is usually used to achieve the breathing light effect. PWM controls the brightness of the output by changing the high time ratio of the signal. The key to realize the breathing light effect is to change the duty cycle of PWM, that is, the ratio of high level time to cycle time.
Use the four LED lights on the development board to realize the breathing light at intervals of 1s.
code:
/*
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
Test file:
`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
Our simulation results through modelsim are as follows:
Among them, we can clearly see that when the flag value is 0, the high-level time ratio is getting smaller and smaller, indicating that the light is gradually turning off; when the flag value is 1, the high-level time ratio is getting larger and larger, indicating that the light is gradually turning on.
The result display: