FPGA產生可調頻率佔空比的PWM
阿新 • • 發佈:2021-10-31
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那些事兒》