如何用FPGA产生PWM波形(增减计数器模式设计)

之前做电机控制都是用DSP产生不同占空比的PWM波形,但是由于项目需要,要用FPGA产生不同占空比的PWM波形,通过查阅资料看到不少的方式方法,综合了一下,按着自己的思路写了一个产生6路3对PWM 波形,并且仿真和实测都满足设计要求。

通常情况下我们的思路是设计一个计数器,增加到一定要求然后置零,往复循环即可,但是,这次有一个问题,为了让达到与DSP的计数模式一致,我们需要设计这个计数器,它先递增,递增到一定数后开始递减,递减到一定数后又递增,循环反复,应该怎么设计呢?其实这个思想不仅仅是在电机控制中有应用,在很多其他地方都能用到,如PWM呼吸灯、VGA方块回弹等。

设计思路:

1.设计一个计数器,根据标志位的不同,进行加1和减1运算。

                                 当标志位为0并且计数器的值小于周期值的一半减1时,计数器+1,

                                 当标志位为1并且计数器的值大于0时,计数器-1,

2.设计一个标志位,当检测到标志位为1,并且计数器也为零时,标志位置0.

                                  当检测到标志位为0,并且计数器为周期值得一般减1时,标志位置1.

3.分别设计三个比较器,其中A、B路波形互补,通过给A、B路的寄存器写入相反的值即可,

考虑到死区问题,要使B路的值小于A路值,此处设置为2us(即100个始终)

代码:

module PWM(
    input               sys_clk  ,  //系统时钟
    input               sys_rst_n,  //系统复位,低电平有效
	 
    output  reg    PWMA_H,    //PWMA路输出
	 output  reg    PWMA_L,
	 
	 output  reg    PWMB_H,    //PWMB路输出
	 output  reg    PWMB_L,
	 
	 output  reg    PWMC_H,    //PWMC路输出
	 output  reg    PWMC_L  
	 
          );
reg [12:0] compar_A=13'd1250;
reg [12:0] compar_B=13'd1250;	
reg [12:0] compar_C=13'd1250; 
reg [12:0] counter;   //计数器用于产生PWM波形所需周期
parameter N =14'd5000;  //设定PWM周期
//*****************************************************
//                      main code
//***************************************************** 


//************************动作模块**********************
reg flag;  
always @(posedge sys_clk or negedge sys_rst_n) 
begin
    if (!sys_rst_n)
        counter <= 13'b0;
    else if (flag == 0 && counter< N/2 -1 )
	     counter <= counter + 1'b1;
	 else if (flag == 1 && counter> 0 )
        counter <= counter - 1'b1;
	
end 
always @(posedge sys_clk or negedge sys_rst_n) 
begin
    if (!sys_rst_n)
        flag <= 1'b0;
    else if (flag == 0 && counter == N/2 -1)
	     flag <= 1;
	 else if (flag == 1 && counter == 0)
        flag <= 0;
	
end 
//*********************6路PWM信号**********************

//*********************A路PWM信号********************** 
always @(posedge sys_clk or negedge sys_rst_n) 
begin
    if (!sys_rst_n)
		 begin
			  PWMA_H <=0;
		 end
    else if (counter>compar_A)   
		 begin
			  PWMA_H <= 1'b1;
		 end
    else
		 begin
			  PWMA_H <= 1'b0;
		 end
	
end	
always @(posedge sys_clk or negedge sys_rst_n) 
begin
    if (!sys_rst_n)
		 begin
			  PWMA_L <=0;
		 end
    else if (counter>compar_A-9'd100)   //死区2us
		 begin
			  PWMA_L <= 1'b0;
		 end
    else
		 begin
			  PWMA_L <= 1'b1;
		 end
	
end	
	
//*********************B路PWM信号********************** 
always @(posedge sys_clk or negedge sys_rst_n) 
begin
    if (!sys_rst_n)
		 begin
			  PWMB_H <=0;
		 end
    else if (counter>compar_B)   
		 begin
			  PWMB_H <= 1'b1;
		 end
    else
		 begin
			  PWMB_H <= 1'b0;
		 end
	
end	
always @(posedge sys_clk or negedge sys_rst_n) 
begin
    if (!sys_rst_n)
		 begin
			  PWMB_L <=0;
		 end
    else if (counter>compar_B-9'd100)   //死区2us
		 begin
			  PWMB_L <= 1'b0;
		 end
    else
		 begin
			  PWMB_L <= 1'b1;
		 end
	
end	
//*********************C路PWM信号********************** 
always @(posedge sys_clk or negedge sys_rst_n) 
begin
    if (!sys_rst_n)
		 begin
			  PWMC_H <=0;
		 end
    else if (counter>compar_C)   
		 begin
			  PWMC_H <= 1'b1;
		 end
    else
		 begin
			  PWMC_H <= 1'b0;
		 end
	
end	
always @(posedge sys_clk or negedge sys_rst_n) 
begin
    if (!sys_rst_n)
		 begin
			  PWMC_L <=0;
		 end
    else if (counter>compar_C-9'd100)   //死区2us
		 begin
			  PWMC_L <= 1'b0;
		 end
    else
		 begin
			  PWMC_L <= 1'b1;
		 end
	
end	
endmodule

 

仿真波形:

可以看出能够产生互补对称得6路PWM波形。

 

上面这个图看出标志位在2500的时候由低变高。

 

上面这个图看出标志位在0的时候由高变低。

上面这个图看出3路PWM_H在比较值的一半减1处由高变低。

上面这个图看出3路PWM_L在PWM_H值小100个数值处由低变高。

示波器测试数据:

上图位3对PWM 波形中的一对,可以看出是互补对称的。

 

上图为局部放大,能够看出死区的存在。

PS:

  一开始设计时没有在counter的触发条件那加上 counter< N/2 -1和 counter> 0  ,结果导致counter  会多计一下,最终功能上稍微有所欠缺,原因是counter和flag两个always块并行跑,如果不加那个限制条件,那flag刚刚拉高时,counter同步变化,实际上还是执行的上一轮限制条件,最终导致结果出错。而加了限制条件后,这个问题就解决了。

 

上述源代码下载点击此处下载(附仿真文件)

评论 32
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贾松(Jason)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值