1. 程式人生 > 其它 >FPGA產生可調頻率佔空比的PWM

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 = 2N* (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那些事兒》