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 / 1psmodule 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) beginif (rst_n == 1'b0) begincnt_ms <= 'd0; endelse if (cnt_ms == CNT_1MS) begincnt_ms <= 'd0;endelse begincnt_ms <= cnt_ms + 1'b1;end
end//----------------------------- cnt_s -----------------------------
always @(posedge clk or negedge rst_n) beginif (rst_n == 1'b0) begincnt_s <= 'd0; endelse if(cnt_ms == CNT_1MS) beginif (cnt_s == CNT_1S) begincnt_s <= 'd0;endelse begincnt_s <= cnt_s + 1'b1;endendelse begincnt_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) beginif (rst_n == 1'b0) beginwork_flag <= 1'b0; endelse if (cnt_s == CHANGE_TIME && cnt_ms == CNT_1MS) beginwork_flag <= 1'b1;endelse if (cnt_s == CNT_1S && cnt_ms == CNT_1MS) beginwork_flag <= 1'b0;endelse beginwork_flag <= work_flag;end
end//----------------------------- duty_cycle -----------------------------
always @(posedge clk or negedge rst_n) beginif (rst_n == 1'b0) beginduty_cycle <= 'd0; endelse if (work_flag == 1'b0) beginif (cnt_ms == CNT_1MS) beginduty_cycle <= duty_cycle + PWM_OFFSET;endelse beginduty_cycle <= duty_cycle;endendelse if (work_flag <= 1'b1) beginif (cnt_ms == CNT_1MS) beginduty_cycle <= duty_cycle - PWM_OFFSET;endelse beginduty_cycle <= duty_cycle;endendelse beginduty_cycle <= duty_cycle;end
end//----------------------------- pwm -----------------------------
always @(posedge clk or negedge rst_n) beginif (rst_n == 1'b0) beginpwm <= 1'b1; endelse if (cnt_ms < duty_cycle) beginpwm <= 1'b1;endelse beginpwm <= 1'b0;end
endendmodule
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呼吸灯