FPGA_学习_09_PWM呼吸灯

PWM在三相电机控制中,有着非常重要的地位。 如果你需要用FPGA去实现三相电机的控制, PWM这一关是绕不过的。好在PWM的基本原理是比较简单的。所以原理部分本文就略过,本文基于PWM实现呼吸灯。

1 时序 

FPGA_学习_09_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呼吸灯

你可能感兴趣的:(FPGA,fpga开发,学习,PWM,呼吸灯)