PWM脉冲调制
PWM——脉宽调制信号(Pulse Width Modulation),它利用微处理器的数字输出来实现,是对模拟电路控制的一种非常有效的技术,广泛应用于测量、通信、功率控制与变化等许多领域。
呼吸灯:采用pwm的方式,在固定的频率下,采用占空比的方式来实现LED亮度的变化。占空比为0,LED灯不亮,占空比为100%,则LED灯最亮。所以将占空比从0到100%,再从100%到0不断变化,就可以实现LED灯实现特效呼吸。
注意这里有几个频率:
1.呼吸周期:即在这个呼吸周期中实现变亮与变暗,比如呼吸周期为2秒,1秒逐渐变亮,1秒逐渐变暗。
2.PWM周期:即在1秒的呼吸周期内(例如1秒逐渐变亮的时间内)有许多PWM周期个时间段,这些时间段的高电平占空比不同,从而实现了逐渐的亮暗变化。
3.PWM精度:即每个相同的PWM周期中,控制亮度不同的是靠PWM周期中高电平的占空比不同来控制的,而相邻的PWM周期中占空比的差值即为精度。
如下图所示,这里PWM周期为1ms,呼吸周期为2s,这里画的为1s内逐渐变亮的过程(1ms中高电平占空比从0逐渐增加到100,由暗变到最亮)
verilog实现
用verilog实现PWM控制呼吸灯。呼吸周期2秒:1秒逐渐变亮,1秒逐渐变暗。系统时钟24MHz,pwm周期1ms,精度1us。
led_out高电平占空比多,led较亮,反之,led较暗,实现呼吸灯效果
module Breath_LED(
input clk, //24Mhz
input rst_n,
output led_out
);
parameter DELAY24 = 24;
//parameter DELAY1000 = 1000;
parameter DELAY1000 = 10;//just test
wire delay_1us;
wire delay_1ms;
wire delay_1s;
reg pwm;
reg [7:0] cnt1;
reg [10:0] cnt2;
reg [10:0] cnt3;
reg display_state;
//延时1us
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt1 <= 6'b0;
else if(cnt1 == DELAY24 - 1'b1)
cnt1 <= 6'b0;
else
cnt1 <= cnt1 + 1'b1;
end
assign delay_1us = (cnt1 == DELAY24 - 1'b1)? 1'b1:1'b0;
//延时1ms
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt2 <= 10'b0;
else if(delay_1us == 1'b1)begin
if(cnt2 == DELAY1000 - 1'b1)
cnt2 <= 10'b0;
else
cnt2 <= cnt2 + 1'b1;
end
else
cnt2 <= cnt2;
end
assign delay_1ms = ((delay_1us == 1'b1) && (cnt2 == DELAY1000 - 1'b1))?
1'b1:1'b0;
//延时1s
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt3 <= 10'b0;
else if(delay_1ms)
begin
if(cnt3 == DELAY1000 - 1'b1)
cnt3 <= 10'b0;
else
cnt3 <= cnt3 + 1'b1;
end
else
cnt3 <= cnt3;
end
assign delay_1s = ((delay_1ms == 1'b1) && (cnt3 == DELAY1000 - 1'b1))?
1'b1:1'b0;
//state change
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
display_state <= 1'b0;
else if(delay_1s)//每一秒切换一次led灯显示状态
display_state <= ~display_state;
else
display_state <= display_state;
end
//pwm信号的产生
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
pwm <= 1'b0;
else
case(display_state)
1'b0: pwm <= (cnt2 < cnt3)? 1'b1:1'b0;
1'b1: pwm <= (cnt2 < cnt3)? 1'b0:1'b1;
default: pwm <= pwm;
endcase
end
//位拼接使得输出八位led呼吸灯
assign led_out = pwm;
endmodule
这里cnt3是在1s内逐渐加一(每1ms加1),即每个pwm周期加1,而cnt2是在每个pwm周期内逐渐增加(每1us加1),所以一开始的pwm周期cnt3较小(cnt2由1增加到1000),所以在一个pwm周期内(cnt2由1增加到1000),cnt2小于cnt3的时间段占比小,所以比较暗(一个pwm周期内,高电平占比小),在后面的PWM周期,cnt3的值逐渐越来越大,在一个pwm周期内(cnt2仍由1增加到1000),此时cnt2小于cnt3的时间段占比大,所以比较亮(一个pwm周期内。高电平占比大)