Verilog实现PWM呼吸灯代码 | FPGA呼吸灯控制与占空比调节教程

通过Verilog代码详解PWM呼吸灯的实现原理,提供完整可运行的模块代码(含时钟分频、占空比动态调节功能),适用于FPGA开发板(如Xilinx、Altera)的LED呼吸灯项目。涵盖仿真步骤、关键参数配置及硬件调试技巧,适合FPGA初学者、电子工程师快速掌握PWM波形生成与硬件描述语言应用。

一、设计文件

module breathing_led
//---------------------<端口声明>---------------------------------------
(
input  wire              clk                , //时钟,50Mhz
input  wire              rst_n              , //复位,低电平有效
output wire              led                   //led灯
);
//---------------------<参数定义>---------------------------------------
parameter TIME_2MS      = 100_000           ; //2ms时间
parameter TIME_2MS_W    = 17                ; //2ms时间位宽
parameter NUM           = 1000              ; //2ms到2s为1000份
parameter NUM_W         = 10                ; //份数位宽
parameter STEP          = 100               ; //2ms也分成1000份,每份为步长100

//---------------------<信号定义>---------------------------------------
reg  [TIME_2MS_W-1:0]   cnt0                ;
wire                    add_cnt0            ;
wire                    end_cnt0            ;
reg  [NUM_W:0]          cnt1                ;
wire                    add_cnt1            ;
wire                    end_cnt1            ;
reg  [1:0]              cnt2                ;
wire                    add_cnt2            ;
wire                    end_cnt2            ;
reg  [TIME_2MS_W-1:0]   pwm_high            ;

//----------------------------------------------------------------------
//--   2ms时间计时
//----------------------------------------------------------------------
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        cnt0 <= 0;
    else if(add_cnt0)begin
        if(end_cnt0)
            cnt0 <= 0;
        else
            cnt0 <= cnt0 + 1;
    end
    else
       cnt0 <= cnt0;
end

assign add_cnt0 = 1;
assign end_cnt0 = add_cnt0 && cnt0==TIME_2MS-1 ;

//----------------------------------------------------------------------
//--   每2ms计1次,计到2秒共需计NUM次
//----------------------------------------------------------------------
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        cnt1 <= 0;
    else if(add_cnt1)begin
        if(end_cnt1)
            cnt1 <= 0;
        else
            cnt1 <= cnt1 + 1;
    end
    else
       cnt1 <= cnt1;
end

assign add_cnt1 = end_cnt0;
assign end_cnt1 = add_cnt1 && cnt1==NUM-1 ;

//----------------------------------------------------------------------
//--   每2秒计1次,计到4秒共需计2次
//----------------------------------------------------------------------
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        cnt2 <= 0;
    end
    else if(add_cnt2)begin
        if(end_cnt2)
            cnt2 <= 0;
        else
            cnt2 <= cnt2 + 1;
    end
    else
       cnt2 <= cnt2;
end

assign add_cnt2 = end_cnt1;
assign end_cnt2 = add_cnt2 && cnt2==2-1 ;

//----------------------------------------------------------------------
//--   设置pwm的占空比时间
//----------------------------------------------------------------------
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        pwm_high <= 0;
    else if(cnt2==0 && end_cnt0)
        pwm_high <= pwm_high + STEP;
    else if(cnt2==1 && end_cnt0)
        pwm_high <= pwm_high - STEP;
    else
        pwm_high <= pwm_high;
end

//----------------------------------------------------------------------
//--   输出led灯
//----------------------------------------------------------------------
assign led = (cnt0 < pwm_high) ? 1'b1 : 1'b0;



endmodule

二、仿真文件

`timescale 1ns/1ps  //时间精度
`define    Clock 20 //时钟周期

module breathing_led_tb;

//---------------------<端口定义>---------------------------------------
reg                     clk                 ; //时钟,50Mhz
reg                     rst_n               ; //复位,低电平有效
wire                    led                 ;

//----------------------------------------------------------------------
//--   模块例化
//----------------------------------------------------------------------
breathing_led
#(
    .TIME_2MS           (1000               ), //2ms时间 100_000
    .NUM                (100                ), //2ms到2s为1000份
    .STEP               (10                 )  //2ms也分成1000份,每份为步长100
)
u_breathing_led
(
    .clk                (clk                ),
    .rst_n              (rst_n              ),
    .led                (led                )
);

//----------------------------------------------------------------------
//--   时钟信号和复位信号
//----------------------------------------------------------------------
initial begin
    clk = 1;
    forever
        #(`Clock/2) clk = ~clk;
end

initial begin
    rst_n = 0; #(`Clock*20+1);
    rst_n = 1;
end




endmodule

三、仿真波形

可以看到led信号的占空比先不断增加后不断减少,循环反复。

Verilog实现PWM呼吸灯代码 | FPGA呼吸灯控制与占空比调节教程 - 第1张

四、上板验证

经过上板验证,最终成功!

本文原创,作者:FPGA小白,其版权均为FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训所有。
如需转载,请注明出处:https://z.shaonianxue.cn/8327.html