PWM呼吸灯

一.PWM原理

  • 在介绍PWM之前,先介绍几个基本概念

1.1PWM频率

  • 是指1秒钟内信号从高电平到低电平再回到高电平的次数(一个周期);
    也就是说一秒钟PWM有多少个周期

1.2PWM周期

  • T=1/f

    周期=1/频率

1.3脉宽周期

  • 高电平的时间

1.4占空比

  • 是一个脉冲周期内,高电平的时间与整个周期时间的比例

1.5PWM原理

  • PWM就是在合适的信号频率下,通过一个周期里改变占空比的方式来改变输出的有效电压

  • PWM实现呼吸灯原理:

    频率很高时,看不到闪烁,占空比越大,LED越亮;

    频率很低时,可看到闪烁,占空比越大,LED越亮。

二.设计思路

  • 设计三个计数器,cnt_us、cnt_ms、cnt_s。其关系为cnt_us计满时cnt_ms自增1;cnt_ms计满时cnt_s自增1。如下图
    在这里插入图片描述

在这里插入图片描述

  • 设计标志信号flag:cnt_s计满时flag反转,以实现渐亮后渐灭。
  • 比较cnt_ms和cnt_s:当cnt_s > cnt_ms时,led灯的值为4’b1111;当cnt_s < cnt_s时,led灯的值为4’b0000;

三.代码实现

module pwm_led(
    input       clk     ,
    input       rst_n   ,
    
    output reg [3:0] led
);

parameter TIME_US = 6'd49;
parameter TIME_MS = 10'd999;
parameter TIME_S = 10'd999;

reg [5:0] cnt_us;
reg [9:0] cnt_ms;
reg [9:0] cnt_s;
reg flag;

//us计数器
wire add_cnt_us;//us计数器开始计数的标志
wire end_cnt_us;//us计数器结束计数的标志

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt_us <= 6'd0;
    end
    else if (add_cnt_us) begin
        if (end_cnt_us) begin
            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;


//ms计数器
wire add_cnt_ms;//ms计数器开始计数的标志
wire end_cnt_ms;//ms计数器结束计数的标志

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;//cnt_us计满时cnt_ms加一
assign end_cnt_ms = add_cnt_ms && cnt_ms == TIME_MS;


//s计数器
wire add_cnt_s;//s计数器开始计数的标志
wire end_cnt_s;//s计数器结束计数的标志

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;//cnt_ms计满时cnt_s加一
assign end_cnt_s = add_cnt_s && cnt_s == TIME_S;

//flag信号当cnt_s计满时反转以实现渐亮后渐灭
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        flag <= 1'b0;
    end
    else if (end_cnt_s) begin
        flag <= ~flag;
    end
    else begin
        flag <= flag;
    end
end

//比较cnt_s和cnt_ms
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        led <= 4'b0000;
    end
    else if(!flag) begin
        led <= (cnt_s > cnt_ms)?4'b1111:4'b0000;
    end
    else if (flag) begin
        led <= (cnt_s > cnt_ms)?4'b0000:4'b1111;
    end
    else begin
        led <= led;
    end
end
endmodule

四.仿真

`timescale 1ns/1ns //单位and精度
module pwm_led_tb();
    
    //激励信号
    reg clk;
    reg rst_n;
    
    //输出信号
    wire [3:0] led;

    //重定义parameter参数,减少仿真时间,便于观察效果
    parameter CYCLE = 20;
    parameter TIME_US = 5;
    parameter TIME_MS = 10;
    parameter TIME_S  = 10;
    
    //生成clk信号,半个周期反转
    always #(CYCLE/2) clk = ~clk;

    //设置激励信号数值
    initial begin
        clk = 1'b0;
        rst_n = 1'b0;
        #(CYCLE);
        rst_n = 1'b1;
        #(2 * (TIME_US + 1) * (TIME_MS + 1) * (TIME_S + 1) * CYCLE);
        $STOP;
    end
    
    //模块例化
    pwm_led #(
        .TIME_US(TIME_US),
        .TIME_MS(TIME_MS),
        .TIME_S(TIME_S)
    ) u_pwm_led(
        .clk(clk),
        .rst_n(rst_n),
        .led(led)
    );
endmodule

五.仿真效果

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值