RTL代码
module breath_led #
(
parameter CLOCK_FRQ = 50_000_000, // 输入时钟频率50M,对应1 Sec
parameter PWM_FRQ = 1000, // PWM频率1K
parameter BREATH_ERIOD = 2, // 呼吸周期 2 Sec
parameter SET_COMPARE_FRQ = 1000, // 比较输出频率 1K
parameter PWM_COUNTER_MAX = CLOCK_FRQ/PWM_FRQ, // PWM发生计数最大值,50_000;一个PWM方波周期 1ms,期间占空比会变化
parameter BREATH_COUNTER_MAX = CLOCK_FRQ*BREATH_ERIOD, // 呼吸计数最大值,100_000_000;2s
parameter SET_COMPARE_COUNTER_MAX = CLOCK_FRQ/SET_COMPARE_FRQ,// 设置的比较计数最大值,50_000;1ms
parameter COMPARE_VALUE_STEP = PWM_COUNTER_MAX/SET_COMPARE_FRQ// 比较值的步长50,对应1us;
)
(
input wire clk,
input wire rstn,
output wire [3:0]led
);
reg [31:0]counter_pwm;
reg [31:0]counter_breath;
reg [31:0]counter_compare;
reg [31:0]compare_value;
reg pwm_period_clk_view; // 没有实际作用
reg breath_period_clk_view; // 没有实际作用
reg compare_period_clk_view; // 没有实际作用
reg [3:0]led_number;
reg led_breath_view;
reg breath_dir;
reg [3:0]led_reg;
assign led = led_reg;
//led的值输出,4路译码器
always @(posedge clk or negedge rstn)
begin
if(rstn==0)led_reg<=0;
case (led_number)
4'b000: led_reg[0]<=led_breath_view;
4'b001: led_reg[1]<=led_breath_view;
4'b010: led_reg[2]<=led_breath_view;
4'b011: led_reg[3]<=led_breath_view;
default: led_reg[0]<=led_breath_view;
endcase
end
//pwm
always @(posedge clk or negedge rstn)
begin
if(rstn==0)
begin
counter_pwm <= 0;
pwm_period_clk_view <= 0;
end
else
begin
counter_pwm <= counter_pwm + 1;
if(counter_pwm < compare_value) led_breath_view <= 1; // compare_value对应占空比,LED high active,compare_value越大越亮
else led_breath_view <= 0;
if(counter_pwm > PWM_COUNTER_MAX-1) // PWM_COUNTER_MAX=50_000,对应1ms
begin
counter_pwm <= 0;
pwm_period_clk_view <= ~pwm_period_clk_view; // 二分频,25MHz
end
end
end
//led输出逻辑
reg [3:0]led_number_state;
always @(posedge clk or negedge rstn)
begin
if(rstn==0)
begin
led_number=0;
counter_breath<=0;
breath_period_clk_view<=0;
breath_dir<=0;
led_number_state<=0;
end
else
begin
counter_breath <= counter_breath + 1;
if(counter_breath > BREATH_COUNTER_MAX-1) // 每2s间隔,LED强度趋势变化一次;0~2s变强,2~4s变弱
begin
counter_breath <= 0;
breath_period_clk_view <= ~breath_period_clk_view;
breath_dir <= ~breath_dir;
if(breath_dir==1)
begin
case (led_number_state)
0: begin led_number_state=1; led_number=0; end
1: begin led_number_state=2; led_number=1; end
2: begin led_number_state=3; led_number=2; end
3: begin led_number_state=4; led_number=3; end
4: begin led_number_state=5; led_number=2; end
5: begin led_number_state=6; led_number=1; end
6: begin led_number_state=0; led_number=0; end
default: begin led_number_state=0; led_number=0; end
endcase
end
end
end
end
//呼吸逻辑和向上向下计数逻辑
always @(posedge clk or negedge rstn)
begin
if(rstn==0)
begin
counter_compare<=0;
compare_period_clk_view<=0;
compare_value<=0;
end
else
begin
counter_compare<=counter_compare+1;
if(counter_compare>SET_COMPARE_COUNTER_MAX-1) // 占空比每隔1ms变化一次
begin
counter_compare<=0;
if(breath_dir==0) // 方向0:PWM占空比越来越大,亮度越来越强,强到一定程度肉眼分辨不出
begin
if(compare_value < PWM_COUNTER_MAX) compare_value <= compare_value + COMPARE_VALUE_STEP; // 占空比每次变化1us
end
else if(breath_dir==1) // 方向1:PWM占空比越来越小,亮度越来越弱,弱到一定程度肉眼认为是灭的
begin
if(compare_value>0)compare_value<=compare_value-COMPARE_VALUE_STEP;
end
compare_period_clk_view<=~compare_period_clk_view;
end
end
end
endmodule
仿真代码
`timescale 1ns / 1ns
module breath_led_tb();
reg clk_reg;
reg rstn_reg;
wire [3:0]led;
wire clk;
wire rstn;
initial begin
clk_reg=0;
rstn_reg=0;
#10
rstn_reg=1;
end
always #10 clk_reg=~clk_reg;
assign rstn=rstn_reg;
assign clk=clk_reg;
breath_led #
(
.CLOCK_FRQ(5_000_000)
)
breath_led_inst
(
.clk(clk),
.rstn(rstn),
.led(led)
);
endmodule
![]()