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波形
posted @ 2022-03-30 17:21  heart-z  阅读(1305)  评论(0编辑  收藏  举报