不枉初心,砥砺前行

皮皮祥的博客

欢迎留言,评论

导航

PWM信号生成电路

一、原理

我们需要两个计数器cnt1cnt2

  • cnt1随系统时钟同步计数(系统时钟上升沿时cnt1加1),范围为0~ T
  • cnt2cnt1的周期同步计数(每当cnt1等于T时,cnt2加1)范围也是0~ T

这样每次cnt10 ~ T的计数时,cnt2为一个固定值,相邻cnt1计数周期对应的cnt2的值逐渐增大,每次将cnt1cnt2进行大小比较,不同比较结果下设置pwm信号为高电平或者低电平即可。

我们将cnt1计数0~T的时间作为脉冲周期,cnt2的值作为脉冲宽度,则占空比 = cnt2/T,占空比从0%---100%(或者100%---0%)的时间 =cnt2*cnt1 = T^2 (单位是clk周期)

二、Verilog代码实现

1、RTL代码

module pwm_gen(clk,rst,pwm);

    input clk;             //系统时钟输入
    input rst;             //复位输出
    output pwm;            //pwm输出

    reg [24:0] cnt1;       //计数器1
    reg [24:0] cnt2;       //计数器2
    reg flag;              //呼吸灯变亮和变暗的标志位

    //这里设置成4,意思就是pwm信号的占空比从100%---0%所需时间是4*4=16个clk周期
    parameter   CNT_NUM = 4;    //也即上文中提到的T值


    //产生计数器cnt1
    always@(posedge clk or negedge rst) begin 
        if(!rst) begin
            cnt1<=13'd0;
        end 
        else begin
             if(cnt1>=CNT_NUM-1) 
                   cnt1<=1'b0;
             else 
                   cnt1<=cnt1+1'b1; 
         end
     end

    //产生计数器cnt2
    always@(posedge clk or negedge rst) begin 
        if(!rst) begin
            cnt2<=13'd0;
            flag<=1'b0;
            end 
        else begin
             if(cnt1==CNT_NUM-1) begin //当计数器1计满时计数器2开始计数加一或减一
                if(!flag) begin //当标志位为0时计数器2递增计数,表示pwm信号占空比逐渐增加
                    //计数器2计满时,表示占空比已最大,标志位变高,之后计数器2开始递减
                    if(cnt2>=CNT_NUM-1) 
                         flag<=1'b1;
                    else
                         cnt2<=cnt2+1'b1;
                end 
                else begin     //当标志位为高时计数器2递减计数
                    if(cnt2<=0)//计数器2级到0,表示占空比已最小,标志位变低,之后计数器2开始递增
                        flag<=1'b0;
                    else 
                        cnt2<=cnt2-1'b1;
                end
             end
             else cnt2<=cnt2; //计数器1在计数过程中计数器2保持不变
        end
    end

    //比较计数器1和计数器2的值产生自动调整占空比输出的信号,即我们想要的pwm信号
    assign  pwm= (cnt1<cnt2)?1'b0:1'b1;

endmodule

2、仿真程序

`timescale  1ns / 1ps

module tb_pwm_gen;

// pwm_gen Parameters
parameter PERIOD   = 10  ;
parameter CNT_NUM  = 4;

// pwm_gen Inputs
reg   clk                                  = 0 ;
reg   rst_n                                = 0 ;

// pwm_gen Outputs
wire  pwm                                  ;


initial
begin
    forever #(PERIOD/2)  clk=~clk;
end

initial
begin
    #(PERIOD*2) rst_n  =  1;
end

pwm_gen #(
    .CNT_NUM ( CNT_NUM ))
 u_pwm_gen (
    .clk                     ( clk   ),
    .rst_n                   ( rst_n ),

    .pwm                     ( pwm   )
);


endmodule

3、仿真结果

仿真时将CNT_NUM设置成了比较小的一个值:4,也是为了方便快速看到结果。

posted on 2022-06-17 17:02  皮皮祥  阅读(240)  评论(0编辑  收藏  举报