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實現
- 先進行管腳約束
- 觀察PWM波形