PWM呼吸灯设计

呼吸灯:
呼吸灯是一种特殊的灯光效果,它可以模拟呼吸的效果,即灯光逐渐由暗变亮再由亮变暗,循环往复。这种效果给人一种柔和、舒缓的感觉,常被应用在装饰、照明和显示等领域。

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仿真结果如下:
PWM呼吸灯设计_第1张图片
其中我们能清晰看出在flag值为0的时候,高电平时间比例越来越小,说明灯在逐渐熄灭,在flag值为1的时候,高电平时间比列越来越大,说明灯在逐渐电亮。

结果展示:

你可能感兴趣的:(fpga开发)