用verilog实现PWM控制呼吸灯。呼吸周期2秒:1秒逐渐变亮,1秒逐渐变暗。系统时钟24MHz,pwm周期1ms,精度1us。
系统时钟为24MHZ,精度为1us,则对24MHZ时钟进行分频为1MHZ,1MHZ对应周期为1us。采用计数器计数,如果计数器从0到23产生一个脉冲表示为1us。
PWM周期为1ms。首先需要完成1ms控制信号,对1us所产生的脉冲信号计数,从0到9时为1ms,产生1ms脉冲信号
1s逐渐变亮 1s逐渐变暗。led周期为1s需要产生1s的周期信号,同上述方式一样,对1ms的信号计数。
基本原理
PWM的全称是脉冲宽度调制(Pulse-width modulation),是通过将有效的电信号分散成离散形式从而来降低电信号所传递的平均功率的一种方式;
所以根据面积等效法则,可以通过对改变脉冲的时间宽度,来等效的获得所需要合成的相应幅值和频率的波形;
具体如下图所示;
由上图可知,脉冲宽度调制使用一个脉冲宽度会被调制的方波,并且波型的平均值会有所变化。
具体实现方式
在本题目中要求PWM载波周期为1ms。而且led灯随着时间再逐渐亮和灭。因此需要PWM在1ms 占空比不断发生变化。1s为周期led发生亮和灭。因此灯的周期为1s。在1s内灯发生亮灭。
//state change 1s为周期控制灯亮和灭,
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
display_state <= 1'b0;
else if(delay_1s)
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) //在1s周期内,控制PWM占空比变换
1'b0: pwm <= (cnt2 < cnt3)?1'b1:1'b0;
1'b1: pwm <= (cnt2 < cnt3)?1'b0:1'b1;
endcase
end
verilog实现
`timescale 1ns / 1ps
module pwm(
input clk,
input rst_n,
output led_out
);
parameter DELAY24 = 24;
parameter DELAY1000 = 10;
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;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
cnt1 <= 6'd0;
else if(cnt1 == DELAY24 - 1'b1)
cnt1 <= 6'd0;
else
cnt1 <= cnt1 + 1'b1;
end
assign delay_1us = (cnt1 == DELAY24 - 1'b1)?1'b1:1'b0;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
cnt2 <= 10'd0;
else
if(delay_1us) begin
if(cnt2 == DELAY1000 - 1'b1)
cnt2 <= 10'd0;
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;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
cnt3 <= 10'd0;
else
if(delay_1ms) begin
if(cnt3 == DELAY1000 - 1'b1)
cnt3 <= 10'd0;
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)
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;
endcase
end
//位拼接使得输出8位led呼吸灯
assign led_out = pwm;
endmodule