FPGA_PWM实现呼吸灯功能(采用计数器生成PWM)

1呼吸灯原理

呼吸灯采用 PWM 的方式, 在固定频率下通过调整占空比的方式来控制 LED灯亮。在由计数器产生的固定周期PWM信号下,如果其占空比为 0, 则 LED灯灭,如果其占空比为100, 则 LED灯最亮。所以将占空比从 0到 100%,再从 100%到 0不断变化,就可以实现 LED灯的 “呼吸 ”效果。 PWM占空比调节示意图如下:

2设计思路

1.采用两个计数器(周期计数器和占空比计数器),周期计数器值与占空比计数器值相比较判断LED的输出电平。(当前周期计数器数值小于等于占空比计数器数值,LED输出高电平) 2.每到达一个周期,占空比计数器递增(或递减)一个步长,实现占空比的变化。

3程序设计

3.1设计程序

在仿真中,周期时间过长会无法看到真实结果,所以设置周期为50,递增递减单位为5。

`timescale 1ns / 1ps

module breath_led(
    input sys_clk,
    input sys_rst_n,
    
    output led
    );
    

reg [15:0] period_cnt;      //周期计数器
reg [15:0] duty_cycle;      //占空比计数器
reg        inc_dec_flag;    //占空比标志位(0递增、1递减)

//周期计数器
always @(posedge sys_clk or negedge sys_rst_n)begin
    if(!sys_rst_n)  //如果复位,周期计数器清零
        period_cnt<=16d0;
    else if(period_cnt==16d50)
        period_cnt<=16d0;
    else
        period_cnt<=period_cnt+1b1;              
end
//根据占空比和计数值之间的大小关系来输出LED
assign   led = (period_cnt >= duty_cycle) ?  1b1  :  1b0;
//占空比计数器
always @(posedge sys_clk or negedge sys_rst_n)begin
    if(!sys_rst_n)begin  //如果复位,占空比计数器和标志位清零
        duty_cycle<=16d0;
        inc_dec_flag<=1b0;
    end
    else begin
        
        if(period_cnt==16d50)begin
            //占空比递增过程(以5为单位递增)
            if(inc_dec_flag==1b0)begin
                if(duty_cycle==16d50)
                    inc_dec_flag<=1b1;
                else
                    duty_cycle<=duty_cycle+16d5;
            end
            //占空比递减过程(以5为单位递减)
            else begin
                if(duty_cycle==16d0)
                    inc_dec_flag<=1b0;
                else
                    duty_cycle<=duty_cycle-16d5;          
            end
        end
    end
end      

endmodule

3.2仿真程序

`timescale 1ns / 1ps

module tb_breath_led(


    );
    
reg sys_clk;
reg sys_rst_n;
wire led;    
    
initial begin
    sys_clk=1b0;
    sys_rst_n=1b0;
    #60 sys_rst_n=1b1;
end   

always #10 sys_clk=~sys_clk;
    
breath_led u_breath_led(
    .sys_clk(sys_clk),
    .sys_rst_n(sys_rst_n),
    
    .led(led)
);    
    
endmodule

4仿真结果

注意:仿真时需要将仿真时间修改为100us

always #10 sys_clk=~sys_clk;

在仿真文件中设置的时钟信号每隔10ns进行一次翻转,也就是说时钟周期为20ns,周期计数器数50个数是一次周期,也就是说一次周期为50*20=1000ns=1us

按照默认设置运行仿真就只能看出1000000ps(1us)内的变化,所以要调整仿真运行时间

最终的仿真波形图如下

经验分享 程序员 微信小程序 职场和发展