1.开发环境
软件:Vivado2019.1
硬件:Zynq7010
仿真:Vivado Simulator
2.预备知识
众所周知,灯的亮度和加在其两端的电压有关。电压越高,亮度越亮,反之越暗。
于是,设计一个呼吸灯就变得很简单了。让IO的输出电平由低到高,再有高到底有规律的变化,就能达到呼吸效果。
现在问题来了,IO的输出电平只有0和3.3V的区别,那么如何让其输出0-3.3V之间的任意电压呢?这就需要用到PWM脉宽调制计数。通俗来讲,就是通过控制一个PWM周期内高电平和低电平的时间来控制其电压。比如一个周期内,高电平时间占50%,那么输出电压为1.65v。
总结:PWM就是在合适的信号频率下,通过一个周期里改变占空比的方式来改变输出的有效电压。
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文件如下:文章来源:https://www.toymoban.com/news/detail-465214.html
`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
可以看到占空比由小变大的过程,说明我们的逻辑是正确的。文章来源地址https://www.toymoban.com/news/detail-465214.html
到了这里,关于【FPGA基础】基于PWM脉宽调制的呼吸灯设计(Vivado)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!