如何用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同步變化,實際上還是執行的上一輪限制條件,最終導致結果出錯。而加了限制條件後,這個問題就解決了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章