1. PWM介绍
PWM是“脉冲宽度调制”的英文缩写,矩形波中高电平脉冲宽度
t
w
t_{w}
tw与周期T的比值叫占空比。占空比用符号p表示
p
=
t
w
/
T
p=t_{w}/T
p=tw/T
当占空比为50%时,称此时的矩形波为方波。0和1交替出现并持续占用相同的时间。
三种不同占空比的矩形波如下图所示
2. 设计分析
我们通过设置分频器中高脉冲的时间就可以得到不同占空比的PWM。
分频器通常是由计时器来实现的,将高频脉冲信号作为时钟信号送入计数器的时钟输入端进行计数,在计数器的输出端就可以得到频率低的信号。设输入信号的时钟信号的频率为
f
i
f_{i}
fi,计数值为N,则输出的最低频率为
f
o
=
f
i
/
N
f_{o}=f_{i}/N
fo=fi/N
对于分频得到的频率一定的矩形波,那我们如何调节其占空比呢?
我可以通过另外一个计数器对高电平脉冲宽度
t
w
t_{w}
tw这段时间内通过的高频率脉冲进行计数,若计数值为a则
t
w
=
a
∗
T
i
=
a
/
f
i
t_{w}=a*T_{i}=a/f_{i}
tw=a∗Ti=a/fi
因此我们可以得到输出的占空比为
p
=
t
w
/
T
o
=
t
w
∗
f
o
=
a
/
f
i
∗
f
i
/
N
=
a
/
N
p=t_{w}/T_{o}=t_{w}*f_{o}=a/f_{i}*f_{i}/N=a/N
p=tw/To=tw∗fo=a/fi∗fi/N=a/N
3. 逻辑设计
module frequency_div(
input clk, //系统时钟
input rst_n, //复位
input En, //分频使能信号
input wire [2:0] sw_fre, //切换频率的开关信号
input wire [1:0] sw_duty, //切换占空比的开关信号
output reg CP_out //矩形波输出
);
reg [7:0] Division;//保存计数分频数值
reg [6:0] Pulse;//保存计数值
reg [6:0] count;
always@(*)
begin
case(sw_fre)
3'b000:Division=8'd4; //4分频
3'b001:Division=8'd8; //8分频
3'b010:Division=8'd16; //16分频
3'b011:Division=8'd32; //32分频
3'b100:Division=8'd64; //64分频
3'b101:Division=8'd128; //128分频
default: Division=8'd4;
endcase
end
always@(*)
begin
case(sw_duty)
2'b00: Pulse=Division/2; //50%占空比
2'b01: Pulse=Division* 3/4; //75%占空比
2'b10: Pulse=Division/4; //25%占空比
2'b11: Pulse=Division/8; //12.5占空比
endcase
end
always@(posedge clk or negedge rst_n) //分频计数
begin
if(!rst_n)
begin
count<=7'd0;
end
else
if(En)
begin
if(count==Division-1'b1)
count<=7'd0;
else
count<=count+1'b1;
end
else
count<=7'd0;
end
always@(posedge clk or negedge rst_n) //占空比计数
begin
if(!rst_n)
begin
CP_out<=1'd0;
end
else
if(En)
begin
if((count>=7'd0)&&(count<Pulse))
CP_out<=7'd1;
else
CP_out<=7'd0;
end
else
CP_out<=7'd0;
end
endmodule
4.testbench测试
`timescale 1ns/1ps
`define clk_period 20
module frequency_div_tb();
reg clk ;
reg rst_n ;
reg En ;
reg [2:0] sw_fre ;
reg [1:0] sw_duty ;
wire CP_out ;
frequency_div frequency_divu1(
.clk(clk), //系统时钟
.rst_n(rst_n), //复位
.En(En), //分频使能信号
.sw_fre(sw_fre), //切换频率的开关信号
.sw_duty(sw_duty), //切换占空比的开关信号
.CP_out(CP_out) //矩形波输出
);
initial clk=1;
always #(`clk_period/2) clk=~clk;
initial
begin
rst_n=0;
En=0;
sw_fre=3'b000;
sw_duty=2'b00;
#(`clk_period*20+1);
rst_n=1;
En=1;
#(`clk_period*20);
En=0;
#(`clk_period);
En=1;
sw_fre=3'b000;
sw_duty=2'b01;
#(`clk_period*20);
En=0;
#(`clk_period);
En=1;
sw_fre=3'b000;
sw_duty=2'b10;
#(`clk_period*20);
En=0;
#(`clk_period);
En=1;
sw_fre=3'b001;
sw_duty=2'b11;
#(`clk_period*40);
En=0;
#(`clk_period);
En=1;
sw_fre=3'b001;
sw_duty=2'b01;
#(`clk_period*40);
En=0;
#(`clk_period);
En=1;
sw_fre=3'b001;
sw_duty=2'b10;
#(`clk_period*40);
En=0;
#(`clk_period);
En=1;
sw_fre=3'b010;
sw_duty=2'b11;
#(`clk_period*60);
$stop;
end
endmodule