PWM波形的FPGA實現


PWM調制,脈寬調制,Pulse Width Modulation,根據相應負載的變化來調制晶體管或MOS管柵極的偏置,來實現晶體管或MOS管導通時間的改變,從而實現開關穩壓電源穩定的輸出。

簡單來說,就是用數字信號對模擬電路進行控制。

PWM介紹

PWM波可以用於控制步進電機的工作。

下圖為一個PWM信號的示意圖,脈沖的周期為Period,脈沖寬度為有效脈沖時間。占空比定義為高電平信號占整個脈沖信號周期的百分比

PWM信號設計

要產生PWM信號,可以用計數器思想,當cnt小於脈沖寬度時,PWM信號為高;當cnt大於脈沖寬度時,PWM信號為低;當cnt=Period-1時,計數器復位,往復循環。

PWM信號發生器系統由占空比、周期調整模塊,PWM信號產生模塊,數碼管顯示模塊。示意圖如下(參考):

按鍵輸入用於控制占空比和周期。Duty是用於控制PWM信號的占空比,Count_P存儲了周期值,Count_D存儲了脈沖寬度的數值,其計算公式為

U2模塊內部有一個計數器cnt1,按照前文的思想,即比較cnt1和Count_P和Count_D的值,即可生成PWM波。

增加了兩個信號,用於選擇顯示數碼管。

程序設計

程序包含頂層模塊與底層模塊,頂層模塊引腳定義如下:

input CLK;
	 input RSTn;			//SW0


     input [3:0] col;
     output [3:0] row;//row =4'b1110
	 input Count_D_Display;		//SW1
	 input Count_P_Display;	//SW2
	 
	 output [7:0]Digitron_Out; 
	 output [3:0]DigitronCS_Out;
	 
	 output PWM_LED_Out;		//LED7
	 output PWM_EPI_Out;		//T4
	 output[6:0] LED_Out;

底層模塊

占空比、周期調整模塊功能如下:隨着key0和key1的按下,duty和Count_P可以改變

module Duty_Period_Adjust_module
(
	CLK, RSTn, AddDuty_In, AddPeriod_In, Duty, Count_P
);
	 input CLK;
	 input RSTn;
	 input AddDuty_In;  //Add Duty Ratio
	 input AddPeriod_In;		//Add Period
	 output reg [7:0]Duty;		//Duty Ratio of PWM
	 output reg [23:0]Count_P;	//period of PWM = Count_P/50_000_000
	 
	 wire neg_AddDuty;    //synthesis keep;
	 wire neg_AddPeriod;  //synthesis keep;

	//KEY0-3按下FPGA引腳輸入電平由高變低,經過消抖模塊的輸出由低變高

	key_filter U1
	(
		.clk( CLK ) ,
		.rstn( RSTn ) ,
		.key_in( AddDuty_In ) ,  			
		.key_deb( neg_AddDuty ) 
	);


	key_filter U2
	(
		.clk( CLK ) ,
		.rstn( RSTn ) ,
		.key_in( AddPeriod_In ) ,			
		.key_deb( neg_AddPeriod ) 
	);

	 
	always @ ( posedge neg_AddDuty or negedge RSTn )
		begin
			if( !RSTn )
				Duty <= 8'd50;
			else if( Duty == 8'd100 )
					Duty <= 8'd0;
				else 		
					Duty <= Duty + 8'd10;
		end

/*******************
While Count_P = 500_000, Period of PWM = 10ms, Frequency of PWM = 100HZ ;
While Count_P = 250_000, Period of PWM = 5ms, Frequency of PWM = 200HZ ;
While Count_P = 50_000, Period of PWM = 1ms, Frequency of PWM = 1000HZ ;
*******************/
	always @ ( posedge neg_AddPeriod or negedge RSTn )
		begin
			if( !RSTn )
				Count_P <= 24'd250_000;
			else if( Count_P == 24'd500_000 )
						Count_P <= 24'd50_000;  
					else 		
						Count_P <= Count_P + 24'd50_000;
		end
		
		
endmodule
		

PWM信號產生模塊如下:利用cnt1與Count_D進行比較,如上所述

module PWM_Generate_module
(
	CLK, RSTn, Duty, Count_P, PWM_Out, Count_D 
);
	 input CLK;
	 input RSTn;
	 input [7:0]Duty; 
	 input [23:0]Count_P; 	//period = Count_P/50_000_000 
	 output reg PWM_Out;
	 output [23:0]Count_D;
	 
	 reg [23:0]Cnt1;

	 
	 assign Count_D = (Duty * Count_P) / 'd100;
	 
	always @ ( posedge CLK or negedge RSTn )
		begin
			if( RSTn == 0 )
				Cnt1 <= 0;
			else if( Cnt1 == Count_P - 1'b1 )
				Cnt1 <= 0;
			else
				Cnt1 <= Cnt1 + 1'b1;
		end
	
	always @( * )
		begin
			if( Cnt1 <= Count_D )
				PWM_Out <= 1'b1;
			else
				PWM_Out <= 0;
		end
	
endmodule

數碼管顯示模塊如下:Count_D_Display, Count_P_Display分別控制數碼管顯示占空比和周期

module Digitron_NumDisplay
(
	CLK, RSTn, Count_D_Display, Count_P_Display, Count_D, Count_P, Duty, Digitron_Out, DigitronCS_Out
);
	input CLK;
	input RSTn;
	input Count_D_Display;
	input Count_P_Display;
	input [23:0]Count_D;
	input [23:0]Count_P;
	input [7:0]Duty;
	output [7:0]Digitron_Out; 
	output [3:0]DigitronCS_Out;


   parameter T1MS = 16'd50000;
	reg [15:0]Cnt;
	reg [3:0]SingleNum;
	reg [7:0]W_Digitron_Out;
	reg [3:0]W_DigitronCS_Out;
	reg [1:0]Display_step ; //數碼管顯示步驟
	parameter _0 = 8'b0011_1111, _1 = 8'b0000_0110, _2 = 8'b0101_1011,
			 	 _3 = 8'b0100_1111, _4 = 8'b0110_0110, _5 = 8'b0110_1101,
			 	 _6 = 8'b0111_1101, _7 = 8'b0000_0111, _8 = 8'b0111_1111,
				 _9 = 8'b0110_1111, _A = 8'b0111_0111, _B = 8'b0111_1100,
				 _C = 8'b0011_1001, _D = 8'b0101_1110, _E = 8'b0111_1001,
				 _F = 8'b0111_0001, _Wu = 8'b0100_0000;
				 


	always @ ( posedge CLK or negedge RSTn )
		begin
			if( !RSTn )
				begin
					Cnt <= 16'd0;
					Display_step <= 2'b00 ;
				end
			else if( Cnt == T1MS )
				begin
					Cnt <= 16'd0;
					if(Display_step == 2'b11)
						Display_step <= 2'b0 ;
					else
						Display_step <=  Display_step +1'b1 ;
				end
			else
				Cnt <= Cnt + 1'b1;
	end
	always@(Display_step)
	begin
			if(!Count_D_Display && !Count_P_Display)//只顯示占空比
				W_DigitronCS_Out  = 4'b1111 ;
			else
			begin
				case (Display_step)		
				2'b00:
					W_DigitronCS_Out = 4'b1110 ;
				2'b01:
					W_DigitronCS_Out = 4'b1101 ;
				2'b10:
					W_DigitronCS_Out = 4'b1011 ;		
				2'b11:
					W_DigitronCS_Out = 4'b0111 ;	
				endcase
			end
	end

	always@(W_DigitronCS_Out)
	begin
			if( Count_D_Display == 1'b1 )					//Digitron Display Count_D				
			begin				
					case(W_DigitronCS_Out)
						4'b1110: SingleNum = Count_D[3:0];
						4'b1101: SingleNum = Count_D[7:4];
						4'b1011: SingleNum = Count_D[11:8];
						4'b0111: SingleNum = Count_D[15:12];
					endcase
			end
			else if( Count_P_Display == 1'b1 )
			begin
					case(W_DigitronCS_Out)
						4'b1110: SingleNum = Count_P[3:0];
						4'b1101: SingleNum = Count_P[7:4];
						4'b1011: SingleNum = Count_P[11:8];
						4'b0111: SingleNum = Count_P[15:12];
					endcase			
			end
			else
			begin
						SingleNum = 5'b11111;				
			end
			case(SingleNum)
					0:  W_Digitron_Out = _0;
					1:  W_Digitron_Out = _1;
					2:  W_Digitron_Out = _2;	 
					3:  W_Digitron_Out = _3;
					4:  W_Digitron_Out = _4;
					5:  W_Digitron_Out = _5;
					6:  W_Digitron_Out = _6;
					7:  W_Digitron_Out = _7;
					8:  W_Digitron_Out = _8;
					9:  W_Digitron_Out = _9;
					10: W_Digitron_Out = _A;
					11: W_Digitron_Out = _B;
					12: W_Digitron_Out = _C;
					13: W_Digitron_Out = _D;
					14: W_Digitron_Out = _E;
					15: W_Digitron_Out = _F;
					default:  W_Digitron_Out = _Wu;
			endcase
	 end
	 
	assign Digitron_Out = W_Digitron_Out;
	assign DigitronCS_Out = W_DigitronCS_Out;
endmodule

FPGA實現

  1. 先進行管腳約束
  2. 觀察PWM波形


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM