FPGA產生可調頻率占空比的PWM


1.PWM產生原理

首先需要一個N比特的計數器,此計數器最大值為2N,最小值為0。為了控制PWM的頻率,需要一個步進值“period”,為了控制占空比,需要一個閾值“duty”。

如下圖所示,計數器(cnt)在每個系統時鍾周期中增加“period”大小,當cnt < duty 時,輸出pwm_out為0,當cnt >= duty 時,輸出pwn_out 置1,調整period和duty的值即可控制PWM波形的頻率和占空比。

計算公式為  period =  2* (Tsysclk / Tpwm) = 2N * (fpwm /fsysclk) , duty = 2N * (1 - DC).

式中Tsysclk、fsysclk為系統時鍾的周期、頻率,Tpwm、fpwm為產生的PWM的周期、頻率,DC為產生PWM的占空比(小於1的數,如30%)。位寬N越大,產生的PWM頻率越准確。

 

 2.Verilog代碼

 1 module pwm
 2 #(
 3     parameter N = 16 //pwm bit width 
 4 )
 5 (
 6     input         clk,
 7     input         rst,
 8     input[N - 1:0]period,    //pwm step value
 9     input[N - 1:0]duty,        //duty value
10     
11     output        pwm_out     //pwm output
12     );
13  
14 reg[N - 1:0] period_r;        //period register
15 reg[N - 1:0] duty_r;        //duty register
16 reg[N - 1:0] period_cnt;    //period counter
17 reg pwm_r;
18 assign pwm_out = pwm_r;
19 always@(posedge clk or posedge rst)
20 begin
21     if(rst==1)
22     begin
23         period_r <= { N {1'b0} };
24         duty_r <= { N {1'b0} };
25     end
26     else
27     begin
28         period_r <= period;
29         duty_r   <= duty;
30     end
31 end
32 //period counter, step is period value
33 always@(posedge clk or posedge rst)
34 begin
35     if(rst==1)
36         period_cnt <= { N {1'b0} };
37     else
38         period_cnt <= period_cnt + period_r;
39 end
40 
41 always@(posedge clk or posedge rst)
42 begin
43     if(rst==1)
44     begin
45         pwm_r <= 1'b0;
46     end
47     else
48     begin
49         if(period_cnt >= duty_r)    //if period counter is bigger or equals to duty value, then set pwm value to high
50             pwm_r <= 1'b1;
51         else
52             pwm_r <= 1'b0;
53     end
54 end
55 
56 endmodule

3.仿真驗證

系統時鍾為50MHz,使用上述代碼產生頻率200Hz,占空比30%的 PWM,取N = 32,計算得period = 17197.87 = 17198,duty = 3006477107

仿真測試代碼

`timescale 1ns / 1ps
module pwm_tb();

parameter   N = 32; //計數器位寬
//reg define
reg         sys_clk  ;
reg         rst     ;
reg [N-1:0] period  ;
reg [N-1:0] duty    ;

//wire define
wire        pwm_out ;

//初始化輸入信號
initial begin
    sys_clk = 1'b1;
    rst     = 1'b1;
    period  = 32'd0;
    duty    = 32'd0;
    #10
    rst     = 1'b0;
    period  = 32'd17198;    //步進值
    duty    = 32'd3_006_477_107; //占空比閾值
end

//sys_clk:模擬系統時鍾,每10ns電平翻轉一次,周期為20ns,頻率為50Mhz
always #10 sys_clk = ~sys_clk;

//例化PWM模塊
pwm
#(
    .N  (N)  //pwm bit width 
)
pwm_inst
(
    .clk    (sys_clk    ),
    .rst    (rst    ),
    .period (period ),   //pwm step value
    .duty   (duty   ),     //duty value

    .pwm_out(pwm_out)   //pwm output
);

endmodule

結果如下圖,波形成功產生

 【參考資料】

1. ALINX 《ZYNQ那些事兒》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM