大侠好,欢迎来到FPGA技术江湖,江湖偌大,相见即是缘分。大侠可以关注FPGA技术江湖,在“闯荡江湖”、"行侠仗义"栏里获取其他感兴趣的资源,或者一起煮酒言欢。
今天给大侠带来基于FPGA的呼吸灯设计,附源码,获取源码,请在“FPGA技术江湖”公众号内回复“呼吸灯设计源码”,可获取源码文件。话不多说,上货。
设计背景
呼吸灯广泛应用于手机之上,并成为各大品牌新款手机的卖点之一。如果手机里面有未处理的通知,比如说未接来电,未查收的短信等等,呼吸灯就会在控制之下完成由亮到暗的逐渐变化,感觉好像是人在呼吸,起到一个通知提醒的作用。
设计原理
关于呼吸灯设计实现的理论主要是PWM有关知识。PWM(Pluse Width Modulation)脉冲宽度调制,是一种对模拟信号电平进行数字编码的方法。通过高分辨率计数器的使用,方波的占空比被调制用来对一个具体模拟信号的电平进行编码。并广泛应用在从测量、通信、功率控制与变换及LED照明等许多领域中。顾名思义,就是占空比可调的信号,那么什么是占空比呢?
占空比(Duty Cycle or Duty Ratio),可以解释为,在一脉冲序列中(方波),正脉冲序列的持续时间与脉冲总周期的比值。也可理解为,电路释放能量的有效时间与总释放时间的比值。
PWM是怎样实现调光呢?想要调节LED的亮度变化,实则是调节控制流经LED的电流。电流增大则LED亮度增强,反之减弱。但由于电流为模拟信号,所以这时就用到了PWM。正如下图所示:
使用一系列等幅不等宽的脉冲来代替一个正弦波,脉冲的宽度根据正弦波a的幅度变化,幅度高,则脉冲宽,反之。
多数负载需要的PWM调制频率都高于10Hz,要想实现呼吸灯的效果,必须提高调制频率,通常调制频率为1Khz~200Khz之间。在LED控制中PWM作用于电源部分,脉宽调制的脉冲频率通常大于100Hz,人眼就不会感到闪烁。这里我们取PWM调制频率为1KHz,PWM周期为1ms。
脉冲频率一定时,输出脉冲的占空比越大,相当于输出的有效电平越大,随着占空比的不同,LED的亮度也将不同。如占空比为0时,则LED不亮,为100%时,则LED最亮,我们让占空比从0~100%变化,再从100%~0不断变化,则就可实现呼吸灯效果。
本设计呼吸灯的一个周期为2s,分为占空比增“吸”和占空比减“呼”两种模式,每个为1s,一个PWM周期为2ms,所以每个模式包含1000个PWM周期,将每个PWM周期分为1000份,即每个时间段2us。
设计框架
设计框架图:50M时钟
设计代码
设计模块huxi_led_state代码:
module huxi_led_state(clk,led,rst_n);input clk;input rst_n;output reg led;parameter T = 100_000;localparam s0 = 1'b0;localparam s1 = 1'b1;reg [25:0] lw;reg [25:0] hw;reg [16:0] count;// 产生2MS的脉冲always @(posedge clk or negedge rst_n)if(!rst_n)begincount <= 1'b0;endelsebeginif(count == T - 1)begincount <= 1'b0;endelsebegincount <= count + 1'b1;endendwire flag;assign flag =(count == T - 1) ? 1'b1:1'b0;reg state;// 通过在一个周期中加减高低电平的时间来产生PWM波always @(posedge clk or negedge rst_n)if(!rst_n)beginlw <= T - 100;hw <= 100;state <= 1'b0;endelsebegincase (state)s0:beginif(flag && (lw > 100)) //判断低电平的时间beginlw <= lw - 100;hw <= hw + 100;state <= s0;endelse if(flag && (lw == 100))beginhw <= hw - 100;lw <= lw + 100;state <= s1;endelsebeginhw <= hw;lw <= lw;state <= s0;endends1:beginif(flag && (hw > 100)) //判断高电平的时间beginhw <= hw - 100;lw <= lw + 100;state <= s1;endelse if(flag && (hw ==100))beginhw <= hw + 100;lw <= lw - 100;state <= s0;endelsebeginhw <= hw;lw <= lw;state <= s1;endenddefault : state <= s0;endcaseendreg [25:0] cnt;reg sum;always @(posedge clk or negedge rst_n)if(!rst_n)beginsum <= 1'b0;led <= 1'b1;cnt <= 1'b0;endelsecase (sum)s0:beginif(cnt < hw -1 )beginled <= 1'b0;cnt <= cnt + 1'b1;endelsebegincnt <= 1'b0;sum <= s1;endends1:beginif(cnt < lw -1)beginled <= 1'b1;cnt <= cnt + 1'b1;endelsebegincnt <= 1'b0;sum <= s0;endenddefault:sum <= s0;endcaseendmodule
仿真测试
测试模块代码:
`timescale 1ns/1psmodule huxi_led_state_tb();reg clk;reg rst_n;wire led;parameter T = 100_000;initial beginclk = 1'b1;rst_n = 1'b0;#200.1 rst_n = 1'b1;endalways #10 clk = ~ clk;huxi_led_state huxi_led_state_date(.clk(clk),.led(led),.rst_n(rst_n));endmodule
仿真图:
仿真中可以看到点亮led等高电平在不停的增高,然后会降低,通过验证我们的设计是正确的。
1173