1 设计要求分析
本次实验的任务为设计一种PWM波形产生逐级递进的占空比,PWM,英文名Pulse Width Modulation,是脉冲宽度调制缩写,PWM波形即占空比从高到低,从低到高的一种数字基带波形信号,可以驱动产生呼吸灯的效果。
2 系统设计
2.1 总体设计思路
实验采用50MHz时钟进行系统仿真,由周期信号计数器,占空比调节模块与PWM波形输出模块构成,由周期信号计数器在时钟驱动下产生一个周期计数值,与占空比调节模块输出的占空比进行比较,来输出特定的PWM信号,同时需要设计一个低电平有效的异步复位信号,当复位信号为低,系统立刻复位。
2.2 接口设计
端口数 | I/O | 功能描述 |
---|---|---|
I_sys_clk | input | 50MHz时钟信号 |
I_sys_rst_n | input | 低电平有效复位信号 |
O_pwm | output | 输出的PWM波形信号 |
2.3 周期信号计数器
输入为I_sys_clk和I_sys_rst_n,均为wire型变量,代表输入时钟和输入低电平有效复位信号,由于要求异步复位,不与时钟同步,所以在always块中,敏感列表包括时钟上升沿时刻和低电平复位信号下降沿。
输出端口为period_cnt,变量类型为reg,在复位信号作用下初始化或者从0计到4后溢出清零,其他情况下将在时钟驱动下自加,即一共有从0到4五个状态。
2.4 占空比调节模块
输入为I_sys_clk和I_sys_rst_n,为wire型变量,以及reg型变量period_cnt,与周期信号计数器相同,占空比调节模块的敏感列表包括时钟上升沿时刻和低电平复位信号下降沿。
输出端口为duty_cycle和duty_cycle_inc_dec_flag,其中前者代表了当前的占空比数值,和计数器一样有从0到4五种状态,分别代表20%,40%,60%,80%,100%的占空比,后者标志了当前的占空比是正在降低还是正在增加,用0代表递增,1代表递减。
在复位信号的下降沿,模块将初始化duty_cyle和duty_cycle_inc_dec_flag为0,即开始从占空比20%递增,在无复位信号同时周期计数器正好计满一个周期后(计数值为4),占空比调节模块将在时钟信号上升沿的驱动下,根据duty_cycle_inc_dec_flag的标志对duty_cycle进行自加或者自减,当自增至最大的4或自减至最小的0时,将duty_cycle_inc_dec_flag的值反转。
2.5 PWM输出模块
输入为duty_cycle和period_cnt,即分别为周期计数器和占空比调节的输出,输出为O_pwm,该模块将两个输入值比较,若占空比值较为大,则输出为1,否则输出为0,用一条assign语句将其赋值给O_pwm。
3 功能仿真测试
3.1 源程序设计
`timescale 1ns / 1ps
module Pwm(
input I_sys_clk,
input I_sys_rst_n,
output O_pwm
);
reg [2:0] period_cnt;
reg [2:0] duty_cycle;
reg duty_cycle_inc_dec_flag;
//PWM输出模块
assign O_pwm = (period_cnt >= duty_cycle) ? 1'b0 :1'b1;
//周期计数器
always @(posedge I_sys_clk or negedge I_sys_rst_n) begin
if(!I_sys_rst_n) begin
period_cnt <= 3'd0;
end
else if(period_cnt == 3'd4) begin
period_cnt <= 3'd0;
end
else begin
period_cnt <= period_cnt+1'b1;
end
end
//占空比调节模块
always @(posedge I_sys_clk or negedge I_sys_rst_n) begin
if(!I_sys_rst_n)begin
duty_cycle <= 3'd0;
duty_cycle_inc_dec_flag <= 3'b0;
end
else begin
if(period_cnt == 3'd4) begin
if(duty_cycle_inc_dec_flag == 1'b0) begin
if(duty_cycle == 3'd4) begin
duty_cycle_inc_dec_flag <= 1'b1;
end
else begin
duty_cycle <= duty_cycle +3'd1;
end
end
else begin
if(duty_cycle == 3'd0) begin
duty_cycle_inc_dec_flag <= 1'b0;
end
else begin
duty_cycle <= duty_cycle -3'd1;
end
end
end
end
end
endmodule
3.2 testbench程序测试
`timescale 1 ps/ 1 ps
module Pwm_tb();
// test vector input registers
reg I_sys_clk;
reg I_sys_rst_n;
// wires
wire O_pwm;
//模块例化
Pwm i1 (
.I_sys_clk(I_sys_clk),
.I_sys_rst_n(I_sys_rst_n),
.O_pwm(O_pwm)
);
initial begin
I_sys_clk = 1'b0;//初始化时钟
I_sys_rst_n = 1'b0;//初始化复位信号
#10 I_sys_rst_n = 1'b1;
end
//50MHz时钟产生
always #10 I_sys_clk =~I_sys_clk;
endmodule
3.3 时序仿真波形
3.4 结果分析
由上面的时序波形图可知,O_pwm会输出占空比从低到高再从高到低的PWM波形
4 思考
如果要求信号占空比的步进为25%(即存在四个状态25%,50%,75%,100%),该如何设计程序并实现?
应该将周期计数器的溢出上限和占空比模块的占空比值上限从4改为3,即以25%的步进产生4种占空比值,代码和仿真图如下:
always @(posedge I_sys_clk or negedge I_sys_rst_n) begin
if(!I_sys_rst_n) begin
period_cnt <= 3'd0;
end
else if(period_cnt == 3'd3) begin//4修改为3
period_cnt <= 3'd0;
end
else begin
period_cnt <= period_cnt+1'b1;
end
end
always @(posedge I_sys_clk or negedge I_sys_rst_n) begin
if(!I_sys_rst_n)begin
duty_cycle <= 3'd0;
duty_cycle_inc_dec_flag <= 3'b0;
end
else begin
if(period_cnt == 3'd3) begin//4修改为3
if(duty_cycle_inc_dec_flag == 1'b0) begin
if(duty_cycle == 3'd3) begin//4修改为3
duty_cycle_inc_dec_flag <= 1'b1;
end
else begin
duty_cycle <= duty_cycle +3'd1;
end
end
else begin
if(duty_cycle == 3'd0) begin
duty_cycle_inc_dec_flag <= 1'b0;
end
else begin
duty_cycle <= duty_cycle -3'd1;
end
end
end
end
end
endmodule
5 技术小结与感想
通过这次实验,了解了状态机的工作原理和编写流程,实现了PWM波形的输出,同时也练习了Vivado的使用。