PWM在三相电机控制中,有着非常重要的地位。 如果你需要用FPGA去实现三相电机的控制, PWM这一关是绕不过的。好在PWM的基本原理是比较简单的。所以原理部分本文就略过,本文基于PWM实现呼吸灯。
1 时序
{signal: [
{name: 'clk', wave: 'p...............................' },
{},
{name: 'rst_n', wave: '01..............................' },
{},
{name: 'cnt_ms', wave: '2.222222222222222222222222222222' , data: ['0','1','2','...','MAX','0','1','2','...','MAX','0','1','2','...','MAX','0','1','2','...','MAX','0','1','2','...','MAX','0','1','2','...','MAX']},
{},
{name: 'cnt_1s', wave: '2.....2....2....2....2....2....2' , data: ['0','1','2','...','MAX','0','1','2','...','MAX']},
{},
{name: 'pwm', wave: '0.....10...1.0..1..0.1....0....1' },
{},
{name: 'duty_cycle', wave: '2.....2....2....2....2....2....2' , data: ['0%','1%','2%','...','100%','99%','98%']},
{},
{name: 'workflag', wave: '0.........................1.....' },
{}
]}
2 FPGA源文件
`timescale 1ns / 1ps
module pwm_led(
input wire clk ,
input wire rst_n ,
output wire [1:0] led
);
//==================================================================
// Parameter define
//==================================================================
localparam CNT_1MS = 50_000 - 1; // 20ns x 50_000 = 1ms
localparam CNT_1S = 1000 - 1; // 1ms x 1000 = 1s
localparam CHANGE_TIME = 500 - 1; // 1ms x 500 = 0.5s
localparam PWM_OFFSET = 100;
//==================================================================
// Internal Signals
//==================================================================
reg [31:0] cnt_ms ;
reg [31:0] cnt_s ;
reg pwm ;
reg [31:0] duty_cycle ;
reg work_flag ;
assign led[1] = ~pwm;
assign led[0] = 1'b0;
//----------------------------- cnt_ms -----------------------------
always @(posedge clk or negedge rst_n) begin
if (rst_n == 1'b0) begin
cnt_ms <= 'd0;
end
else if (cnt_ms == CNT_1MS) begin
cnt_ms <= 'd0;
end
else begin
cnt_ms <= cnt_ms + 1'b1;
end
end
//----------------------------- cnt_s -----------------------------
always @(posedge clk or negedge rst_n) begin
if (rst_n == 1'b0) begin
cnt_s <= 'd0;
end
else if(cnt_ms == CNT_1MS) begin
if (cnt_s == CNT_1S) begin
cnt_s <= 'd0;
end
else begin
cnt_s <= cnt_s + 1'b1;
end
end
else begin
cnt_s <= cnt_s;
end
end
//----------------------------- work_flag -----------------------------
// 0 ~ 0.5s work_flag == 0
// 0.5s ~ 1s work_flag == 1
always @(posedge clk or negedge rst_n) begin
if (rst_n == 1'b0) begin
work_flag <= 1'b0;
end
else if (cnt_s == CHANGE_TIME && cnt_ms == CNT_1MS) begin
work_flag <= 1'b1;
end
else if (cnt_s == CNT_1S && cnt_ms == CNT_1MS) begin
work_flag <= 1'b0;
end
else begin
work_flag <= work_flag;
end
end
//----------------------------- duty_cycle -----------------------------
always @(posedge clk or negedge rst_n) begin
if (rst_n == 1'b0) begin
duty_cycle <= 'd0;
end
else if (work_flag == 1'b0) begin
if (cnt_ms == CNT_1MS) begin
duty_cycle <= duty_cycle + PWM_OFFSET;
end
else begin
duty_cycle <= duty_cycle;
end
end
else if (work_flag <= 1'b1) begin
if (cnt_ms == CNT_1MS) begin
duty_cycle <= duty_cycle - PWM_OFFSET;
end
else begin
duty_cycle <= duty_cycle;
end
end
else begin
duty_cycle <= duty_cycle;
end
end
//----------------------------- pwm -----------------------------
always @(posedge clk or negedge rst_n) begin
if (rst_n == 1'b0) begin
pwm <= 1'b1;
end
else if (cnt_ms < duty_cycle) begin
pwm <= 1'b1;
end
else begin
pwm <= 1'b0;
end
end
endmodule
3 约束文件
create_clock -period 20.000 [ get_ports clk ]
set_property PACKAGE_PIN N18 [ get_ports clk ]
set_property PACKAGE_PIN P15 [ get_ports {led[0]} ]
set_property PACKAGE_PIN U12 [ get_ports {led[1]} ]
set_property PACKAGE_PIN T12 [ get_ports rst_n ]
set_property IOSTANDARD LVCMOS33 [ get_ports clk ]
set_property IOSTANDARD LVCMOS33 [ get_ports {led[*]} ]
set_property IOSTANDARD LVCMOS33 [ get_ports rst_n ]
4 运行结果
PWM呼吸灯