FPGA PWM呼吸灯
1. MATLAB仿真
首先对该PWM算法进行验证,载波和调制信号均为三角波,频率相差50倍。
f=50000;%时钟频率 num=10;%重复周期数 radio=50;%调制比 carrier=zeros(1,f/radio);%载波 for i=1:(f/radio) if i<=(f/(2*radio)) carrier(i)=i; else carrier(i)=(f/radio)-i; end end modulating=repelem(carrier,radio);%调制信号 carrier=repmat(carrier,1,radio); time=0:1/f:num-1/f; output=zeros(f,1);%PWM输出 output(1)=1; for i=2:f if((carrier(i)>modulating(i) && carrier(i-1)<=modulating(i-1)) || ... (carrier(i)<modulating(i) && carrier(i-1)>=modulating(i-1))) output(i)=~output(i-1); else output(i)=output(i-1); end end output=repmat(output,num,1); PWM=timeseries(output,time');
绘出图像,如下图所示,可以看到输出信号占空比先增大后减小,输出信号均值跟随调制信号变化。
subplot(2,1,1); stairs((0:f-1)/f,[carrier;modulating]'); subplot(2,1,2); plot((0:f-1)/f,output(1:f)); ylim([-0.2,1.2]);
2. Simulink验证
在Simulink中构建一个简单的电路模型,对波形进行观察。
观察电流波形,可以看到其接近三角波,PWM调制结果正确。
3. 源文件
将上面的算法用Verilog进行描述。
carrier为载波,modulating为调制信号,flag_c指示carrier处于上升沿还是下降沿,同样,flag_m指示modulating的状态。
clk上升沿到来,carrier变化一次,radio加一;radio计数达50,modulating变化一次。
module breath_led( output reg led = 1'b0, // LED1, 1 on, 0 off input clk, // FPGA PL clock, 50 MHz input rst_n // FPGA reset pin ); reg [18:0] carrier = 19'b0; reg [18:0] modulating = 19'b0; reg [5:0] radio = 6'b0; reg flag_c = 0; reg flag_m = 0; //clock input 50000000 parameter CLOCK_FREQ = 50000000; parameter COUNTER_MAX = CLOCK_FREQ/100; always @(posedge clk, negedge rst_n) begin if(!rst_n) begin carrier <= 19'b0; flag_c <= 0; end else begin if(flag_c == 0) carrier <= carrier + 1'b1; else carrier <= carrier - 1'b1; if(carrier == COUNTER_MAX-1) flag_c <= 1; else if(carrier == 1) flag_c <= 0; end end always @(posedge clk, negedge rst_n) begin if(!rst_n) begin radio <= 6'b0; modulating <= 19'b0; flag_m <= 0; end else begin if(radio == 49) begin radio <= 6'b0; if(flag_m == 0) modulating <= modulating + 1'b1; else modulating <= modulating - 1'b1; if(modulating == COUNTER_MAX-1) flag_m <= 1; else if(modulating == 1) flag_m <= 0; end else radio <= radio + 1'b1; end end always @(posedge clk, negedge rst_n) begin if(!rst_n) begin led <= 1'b0; end else begin if(carrier>modulating) led <= 1'b0; if(carrier<modulating) led <= 1'b1; end end endmodule
4. 仿真文件
`define clk_cycle 10 module breath_led_sim(); reg clk, rst_n; wire led; always #`clk_cycle clk = ~clk; initial begin clk = 0; rst_n = 1; #10 rst_n = 0; #10 rst_n = 1; end breath_led breath_led(.rst_n(rst_n), .clk(clk), .led(led)); endmodule
仿真1s,观察波形,如下图所示。与MATLAB计算结果相一致。