FPGA_PWM实现呼吸灯功能(采用计数器生成PWM)
1呼吸灯原理
呼吸灯采用 PWM 的方式, 在固定频率下通过调整占空比的方式来控制 LED灯亮。在由计数器产生的固定周期PWM信号下,如果其占空比为 0, 则 LED灯灭,如果其占空比为100, 则 LED灯最亮。所以将占空比从 0到 100%,再从 100%到 0不断变化,就可以实现 LED灯的 “呼吸 ”效果。 PWM占空比调节示意图如下:
2设计思路
1.采用两个计数器(周期计数器和占空比计数器),周期计数器值与占空比计数器值相比较判断LED的输出电平。(当前周期计数器数值小于等于占空比计数器数值,LED输出高电平) 2.每到达一个周期,占空比计数器递增(或递减)一个步长,实现占空比的变化。
3程序设计
3.1设计程序
在仿真中,周期时间过长会无法看到真实结果,所以设置周期为50,递增递减单位为5。
`timescale 1ns / 1ps
module breath_led(
input sys_clk,
input sys_rst_n,
output led
);
reg [15:0] period_cnt; //周期计数器
reg [15:0] duty_cycle; //占空比计数器
reg inc_dec_flag; //占空比标志位(0递增、1递减)
//周期计数器
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n) //如果复位,周期计数器清零
period_cnt<=16d0;
else if(period_cnt==16d50)
period_cnt<=16d0;
else
period_cnt<=period_cnt+1b1;
end
//根据占空比和计数值之间的大小关系来输出LED
assign led = (period_cnt >= duty_cycle) ? 1b1 : 1b0;
//占空比计数器
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)begin //如果复位,占空比计数器和标志位清零
duty_cycle<=16d0;
inc_dec_flag<=1b0;
end
else begin
if(period_cnt==16d50)begin
//占空比递增过程(以5为单位递增)
if(inc_dec_flag==1b0)begin
if(duty_cycle==16d50)
inc_dec_flag<=1b1;
else
duty_cycle<=duty_cycle+16d5;
end
//占空比递减过程(以5为单位递减)
else begin
if(duty_cycle==16d0)
inc_dec_flag<=1b0;
else
duty_cycle<=duty_cycle-16d5;
end
end
end
end
endmodule
3.2仿真程序
`timescale 1ns / 1ps
module tb_breath_led(
);
reg sys_clk;
reg sys_rst_n;
wire led;
initial begin
sys_clk=1b0;
sys_rst_n=1b0;
#60 sys_rst_n=1b1;
end
always #10 sys_clk=~sys_clk;
breath_led u_breath_led(
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.led(led)
);
endmodule
4仿真结果
注意:仿真时需要将仿真时间修改为100us
always #10 sys_clk=~sys_clk;
在仿真文件中设置的时钟信号每隔10ns进行一次翻转,也就是说时钟周期为20ns,周期计数器数50个数是一次周期,也就是说一次周期为50*20=1000ns=1us
按照默认设置运行仿真就只能看出1000000ps(1us)内的变化,所以要调整仿真运行时间
最终的仿真波形图如下
