【FPGA/verilog -入门学习12】Verilog可配置的PWM设计,参数传递的3种方式

发布时间:2023年12月18日

需求:

基于任务(task)的PWM设计仿真验证

需求分析:

1,需求实现可配置PWM输出(频率,占空比)

2,输入,输出端口

input i_clk, //clk = 50Mhz

input i_rst_n,

input i_en,

output reg o_vld,//有效信号

output reg o_pwm

3,定义计数寄存器reg [7:0]cnt;

用于计数,0~ 分频最大值,

o_pwm 在计数到0~正数占空比来临前置高,其他时间置低

4,o_vld 在最高计数来临时,置高,其他时间置低

实现方案1,使用参数传递方式,将最大计数值和高脉冲占空比计数值通过 参数传递出去

vlg_design

/
/*
    实现pwm 350kHZ,占空比50%的输出
 */
/
`timescale 1ns/1ps

module vlg_design #(
parameter CNT_MAX = 50_000_000/350_000 - 1 , //350Khz计数值,
parameter CNT_MAX_PERCENT = 50_000_000/350_000*0.5 -1 //50%占空比
)
(
    input i_clk,     //clk = 50Mhz
    input i_rst_n,
    input i_en,
    output reg o_vld,    //有效信号
    output reg o_pwm
    );


reg [7:0]cnt;
always@(posedge i_clk) begin
    if(!i_rst_n) cnt <= 'b0;
    else if(!i_en) cnt <= 'b0;
    else if(cnt < CNT_MAX) cnt <= cnt+1'b1;
    else cnt <= 'b0;
end 

always@(posedge i_clk) begin
    if(!i_rst_n) o_pwm <= 'b0;
    else if(!i_en) o_pwm <= 'b0;
    else if(cnt <= CNT_MAX_PERCENT) o_pwm <= 1'b1;
    else o_pwm <= 'b0;
end 
    
always@(posedge i_clk) begin
    if(!i_rst_n) o_vld <= 'b0;
    else if(!i_en) o_vld <= 'b0;
    else if(cnt == CNT_MAX) o_vld <= 1'b1;
    else o_vld <= 'b0;
end 

endmodule

testbench_top

`timescale 1ns/1ps
module testbench_top();


//参数定义
 `define CLK_PERIORD 20    //50Mhz

localparam  CNT_500KHZ_MAX =  50_000_000/500_000 - 1 ; //350Khz计数值
localparam CNT_500KHZ_MAX_10_PERCENT =  50_000_000/500_000*0.1 -1  ;//50%占空比

//接口申明
reg i_clk;
reg i_rst_n;
reg i_en;
wire o_vld;    //有效信号
wire o_pwm;

vlg_design  #(
.CNT_MAX (CNT_500KHZ_MAX),
.CNT_MAX_PERCENT(CNT_500KHZ_MAX_10_PERCENT)
)
vlg_design_inst(
    .i_clk(i_clk),
    .i_rst_n(i_rst_n),
    .i_en(i_en),
    .o_vld(o_vld),
    .o_pwm(o_pwm) 
    );        
 
initial  begin
i_en <= 0;
i_clk <= 0;
i_rst_n <= 0;
#200;
i_rst_n <= 1;
end
always #(`CLK_PERIORD/2) i_clk = ~i_clk;
//产生激励
initial begin
    @(posedge i_clk);
    @(posedge i_rst_n);    
    i_en <= 1;
    @(posedge i_clk);    
    #5_000;
    i_en <= 0;
    $stop;
end

endmodule
 

实现方案2,将配置分频计数的参数和占空比高脉冲计数参数,配置位输入port,在测试文件中,使用task任务的方式对其赋不同的值,实现参数配置生成不同的PWM信号

vlg_design

/
/*
    实现pwm 350kHZ,占空比50%的输出
 */
/
`timescale 1ns/1ps
module vlg_design (
    input [7:0] i_cnt_max,
    input [7:0] i_cnt_max_percent,
    input i_clk,     //clk = 50Mhz
    input i_rst_n,
    input i_en,
    output reg o_vld,    //有效信号
    output reg o_pwm
    );

reg [7:0]cnt;
always@(posedge i_clk) begin
    if(!i_rst_n) cnt <= 'b0;
    else if(!i_en) cnt <= 'b0;
    else if(cnt < i_cnt_max) cnt <= cnt+1'b1; 
    else cnt <= 'b0;
end 

always@(posedge i_clk) begin
    if(!i_rst_n) o_pwm <= 'b0;
    else if(!i_en) o_pwm <= 'b0;
    else if(cnt <= i_cnt_max_percent) o_pwm <= 1'b1;
    else o_pwm <= 'b0;
end 
    
always@(posedge i_clk) begin
    if(!i_rst_n) o_vld <= 'b0;
    else if(!i_en) o_vld <= 'b0;
    else if(cnt == i_cnt_max) o_vld <= 1'b1;
    else o_vld <= 'b0;
end 

endmodule

testbench_top

`timescale 1ns/1ps
module testbench_top();

//参数定义
 `define CLK_PERIORD 20    //50Mhz

localparam  CNT_500KHZ_MAX =  50_000_000/500_000 - 1 ; //500Khz计数值
localparam CNT_500KHZ_MAX_10_PERCENT =  50_000_000/500_000*0.5 -1  ;//50%占空比

localparam  CNT_350KHZ_MAX =  50_000_000/350_000 - 1 ; //350Khz计数值
localparam CNT_350KHZ_MAX_10_PERCENT =  50_000_000/350_000*0.1 -1  ;//10%章 ?空比

//接口申明
reg [7:0] i_cnt_max;
reg [7:0] i_cnt_max_percent;
reg i_clk;
reg i_rst_n;
reg i_en;
wire o_vld;    //有效信号
wire o_pwm;

vlg_design vlg_design_inst(
    .i_cnt_max(i_cnt_max),
    .i_cnt_max_percent(i_cnt_max_percent),
    .i_clk(i_clk),
    .i_rst_n(i_rst_n),
    .i_en(i_en),
    .o_vld(o_vld),
    .o_pwm(o_pwm) 
    );        

task setpwmparam;
    input [7:0]t_cnt_max;
    input [7:0]t_cnt_max_percent;
    begin
    
    i_cnt_max <= t_cnt_max;
    i_cnt_max_percent <= t_cnt_max_percent;
    @(posedge i_clk);    
    i_en <= 1;
    repeat(t_cnt_max*2) @(posedge i_clk);
    i_en <= 0;
    end
endtask 

initial  begin
i_en <= 0;
i_clk <= 0;
i_rst_n <= 0;
#200;
i_rst_n <= 1;
end

always #(`CLK_PERIORD/2) i_clk = ~i_clk;
//产生激励
initial begin
    @(posedge i_clk);
    @(posedge i_rst_n);    
    setpwmparam(CNT_500KHZ_MAX,CNT_500KHZ_MAX_10_PERCENT);
    #200;    
    setpwmparam(CNT_350KHZ_MAX,CNT_350KHZ_MAX_10_PERCENT);
    #20000;
    $stop;
end

endmodule
 

方案3:使用vivado VIO功能传递参数

步骤1,添加设计文件到vivado工程

步骤2,添加vio ip核

步骤2,复制veo文件下的例化模板至设计文件中

去掉模块定义中的这4个输入,改为VIO提供,由软件控件配置参数,通过JTAG 线缆,传递给芯片

步骤3,运行综合

步骤4,管脚分配

步骤5,生成bit文件,并烧录

步骤6,添加vio按钮

将i_en 配置成按钮button ,按下是高电平

其他3个配置位,10进制输入

点击i_en 开始测试

文章来源:https://blog.csdn.net/cengqiu4314/article/details/134994849
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。