【FPGA基础】基于PWM脉宽调制的呼吸灯设计(Vivado)

基于PWM脉宽调制的呼吸灯设计(Vivado)

  • 1.开发环境
  • 2.预备知识
  • 3.思路介绍
  • 4.verliog代码
  • 5.仿真

1.开发环境

软件:Vivado2019.1
硬件:Zynq7010
仿真:Vivado Simulator

2.预备知识

众所周知,灯的亮度和加在其两端的电压有关。电压越高,亮度越亮,反之越暗。
于是,设计一个呼吸灯就变得很简单了。让IO的输出电平由低到高,再有高到底有规律的变化,就能达到呼吸效果。
现在问题来了,IO的输出电平只有0和3.3V的区别,那么如何让其输出0-3.3V之间的任意电压呢?这就需要用到PWM脉宽调制计数。通俗来讲,就是通过控制一个PWM周期内高电平和低电平的时间来控制其电压。比如一个周期内,高电平时间占50%,那么输出电压为1.65v。

总结:PWM就是在合适的信号频率下,通过一个周期里改变占空比的方式来改变输出的有效电压。

【FPGA基础】基于PWM脉宽调制的呼吸灯设计(Vivado)_第1张图片

3.思路介绍

一般人眼睛对于80Hz 以上刷新频率则完全没有闪烁感。

举个例子:

如果在1秒内,高电平0.5秒,低电平0.5秒,(频率1Hz)如此反复,那么你看到的电灯就会闪烁,
但是如果是10毫秒内,5毫秒打开,5毫秒关闭,(频率100Hz) 这时候灯光的亮灭速度赶不上开关速度(LED灯还没完全亮就又熄灭了),由于视觉暂留作用 人眼不感觉电灯在闪烁,而是感觉灯的亮度少了。

既然如此,那我们就采用频率为100hz的PWM波形对电压进行调制。对应的周期为10ms,也就是说10ms内灯的亮度不变(占空比不变),每隔10ms占空比变化一次。如果我们设定满占空比为100,那么整个呼吸灯的周期为2×10ms×100=2s。换句话说,从暗-亮-暗的时间为2s。

ZYNQ的PL端的板载晶振为50mhz,按照以上的思路,我们需要设计一个周期为10ms的定时器,来更新占空比

设计模块的常量如下:

    parameter CLOCK_FREQ = 50000000;//周期20ms,也就是说20ms内比较值不变
    parameter PWM_FREQ = 100;//100hz 
    parameter PERIOD = CLOCK_FREQ / PWM_FREQ - 1;//10ms定时计数
    parameter FULL_DUTY = 100;//满占空比
    parameter STEP = PERIOD / FULL_DUTY;//步长5000

4.verliog代码

module breath_led(
    input clk,
    input rst,
    output reg [3:0] led
    );
    parameter CLOCK_FREQ = 50000000;//周期20ms,也就是说20ms内比较值不变
    parameter PWM_FREQ = 100;//100hz 
    parameter PERIOD = CLOCK_FREQ / PWM_FREQ - 1;//10ms定时计数
    parameter FULL_DUTY = 100;//满占空比
    parameter STEP = PERIOD / FULL_DUTY;//步长5000
    
    reg [19:0] compare;
    reg [19:0] counter;//10ms定时
    reg [6:0] now_duty;//占空比计数
    reg flag = 1'b1;//方向标志
    
    always@(posedge clk or negedge rst) begin
        if(!rst) begin
            compare <= 20'd0;
            counter <= 20'd0;
            now_duty <= 7'd0;     
        end
        else begin
            counter <= counter + 1'b1;
            if(counter == PERIOD) begin
                if(flag) begin
                    now_duty <= now_duty + 1'b1;
                    compare <= compare + 14'd5000;
                    counter <= 20'd0;
                end
                else begin
                    now_duty <= now_duty - 1'b1;
                    compare <= compare - 14'd5000;
                    counter <= 20'd0;           
                end
            end    
        end   
    end
    
    always@(counter) begin
        if(counter < compare) begin
            led <= 4'b1111;      
        end
        else begin
            led <= 4'b0000;           
        end
    end
    
    always@(now_duty) begin
        if(now_duty == FULL_DUTY) begin
            flag = 1'b0;
        end
        if(now_duty == 0) begin
            flag = 1'b1;
        end
    end
       
endmodule

5.仿真

testbench文件如下:

`timescale 1ns / 1ps

module breath_led_tb();

reg clk_reg;
reg rst_reg;
wire [3:0] led;

wire clk;
wire rst;

initial begin
clk_reg = 0;
rst_reg = 0;
#10
rst_reg = 1;
end

always #1 clk_reg=~clk_reg;
assign rst = rst_reg;
assign clk = clk_reg;

breath_led test
(
.clk(clk),
.rst(rst),
.led(led)
);
endmodule

【FPGA基础】基于PWM脉宽调制的呼吸灯设计(Vivado)_第2张图片
可以看到占空比由小变大的过程,说明我们的逻辑是正确的。

你可能感兴趣的:(FPGA,fpga开发,硬件工程,PWM,zyqn)