PWM信号生成电路
一、原理
我们需要两个计数器cnt1
和cnt2
:
cnt1
随系统时钟同步计数(系统时钟上升沿时cnt1
加1),范围为0~ T
;cnt2
随cnt1
的周期同步计数(每当cnt1
等于T
时,cnt2
加1)范围也是0~ T
;
这样每次cnt1
在0 ~ T
的计数时,cnt2
为一个固定值,相邻cnt1
计数周期对应的cnt2
的值逐渐增大,每次将cnt1
和cnt2
进行大小比较,不同比较结果下设置pwm
信号为高电平或者低电平即可。
我们将cnt1
计数0~T
的时间作为脉冲周期,cnt2
的值作为脉冲宽度,则占空比 = cnt2/T
,占空比从0%---100%(或者100%---0%)的时间 =cnt2*cnt1 = T^2 (单位是clk周期)
。
二、Verilog代码实现
1、RTL代码
module pwm_gen(clk,rst,pwm);
input clk; //系统时钟输入
input rst; //复位输出
output pwm; //pwm输出
reg [24:0] cnt1; //计数器1
reg [24:0] cnt2; //计数器2
reg flag; //呼吸灯变亮和变暗的标志位
//这里设置成4,意思就是pwm信号的占空比从100%---0%所需时间是4*4=16个clk周期
parameter CNT_NUM = 4; //也即上文中提到的T值
//产生计数器cnt1
always@(posedge clk or negedge rst) begin
if(!rst) begin
cnt1<=13'd0;
end
else begin
if(cnt1>=CNT_NUM-1)
cnt1<=1'b0;
else
cnt1<=cnt1+1'b1;
end
end
//产生计数器cnt2
always@(posedge clk or negedge rst) begin
if(!rst) begin
cnt2<=13'd0;
flag<=1'b0;
end
else begin
if(cnt1==CNT_NUM-1) begin //当计数器1计满时计数器2开始计数加一或减一
if(!flag) begin //当标志位为0时计数器2递增计数,表示pwm信号占空比逐渐增加
//计数器2计满时,表示占空比已最大,标志位变高,之后计数器2开始递减
if(cnt2>=CNT_NUM-1)
flag<=1'b1;
else
cnt2<=cnt2+1'b1;
end
else begin //当标志位为高时计数器2递减计数
if(cnt2<=0)//计数器2级到0,表示占空比已最小,标志位变低,之后计数器2开始递增
flag<=1'b0;
else
cnt2<=cnt2-1'b1;
end
end
else cnt2<=cnt2; //计数器1在计数过程中计数器2保持不变
end
end
//比较计数器1和计数器2的值产生自动调整占空比输出的信号,即我们想要的pwm信号
assign pwm= (cnt1<cnt2)?1'b0:1'b1;
endmodule
2、仿真程序
`timescale 1ns / 1ps
module tb_pwm_gen;
// pwm_gen Parameters
parameter PERIOD = 10 ;
parameter CNT_NUM = 4;
// pwm_gen Inputs
reg clk = 0 ;
reg rst_n = 0 ;
// pwm_gen Outputs
wire pwm ;
initial
begin
forever #(PERIOD/2) clk=~clk;
end
initial
begin
#(PERIOD*2) rst_n = 1;
end
pwm_gen #(
.CNT_NUM ( CNT_NUM ))
u_pwm_gen (
.clk ( clk ),
.rst_n ( rst_n ),
.pwm ( pwm )
);
endmodule
3、仿真结果
仿真时将CNT_NUM设置成了比较小的一个值:4,也是为了方便快速看到结果。