一、基本原理
FPGA板载LED灯的亮暗可以由电压控制,电压高时会比较亮,FPGA较难直接控制端口电压,所以通过PWM波不同的占空比来模拟电压的高低。
二、实验目标
今天所用板卡为高云的Tang primer 20k,根据板卡原理图可知,当LED端口为0时灯泡亮起。
我们希望灯泡可以在一秒内缓缓亮起,然后在一秒内缓缓暗去,当然这个时间可以自定义。
三、实验分析
为了体现占空比的变化,也就是电压的变化,可以将亮起的一秒钟分成若干等分,每一份的占空比依次递减,直到最后一份整个时间段里全为0。同理,可以将熄灭的一秒钟也分成若干等分(不必和亮起一致,看自己需求,本实验亮起和熄灭分成相同等分),占空比依次递增,直到最后整个时间段里全为1。这里将一秒分为1000份,在一定的范围内,份数越多,效果越细腻。
时钟为27Mhz,1s等于27×10的6次方个周期,分成1000份,每一份就有27×10的3次方个周期,让其PWM波占空比依次减小,第一个时间段内占空比应该为1,也就是27×10的3次方个周期LED均为1。第二个时间段内选取其中一小部分为0,为了呼吸灯效果的均匀,每一个时间段为0的周期数应该比前一个多27个时钟周期,这样到最后一个时间段内占空比就接近于0,也就是完全亮的状态。
四、代码
module breath_led(
input wire sys_clk ,
input wire sys_rst_n ,
output reg led );
parameter base=27,
max1=27_000,
max2=1000;
reg [14:0] cnt1 ;//每个时间段内的周期数
reg [9:0] cnt2 ;//总时间段数
reg flag ;//判断现在时亮起状态还是熄灭状态的标志
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
flag<=1'b0;
else if(cnt2==max2-2'd2&&cnt1==max1-1'b1)
flag<=1'b1;
else if(cnt2==1&&cnt1==max1-1'b1&&flag==1'b1)
flag<=1'b0;
else
flag<=flag;
end
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt1<=15'b0;
else if(cnt1==max1-1'b1)
cnt1<=15'b0;
else
cnt1<=cnt1+1'b1;
end
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt2<=10'b0;
else if(cnt1==max1-1'b1&&flag==1'b0)
cnt2<=cnt2+1'b1;
else if(cnt1==max1-1'b1&&flag==1'b1)
cnt2<=cnt2-1'b1;
else
cnt2<=cnt2;
end
always@(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
led<=1'b1;
else if(cnt1<=base*cnt2)
led<=1'b0;
else
led<=1'b1;
end
endmodule
五、测试代码
`timescale 1ns/1ns
module breath_led_tb();
reg sys_clk ;
reg sys_rst_n ;
wire led ;
breath_led breath_led_inst(
. sys_clk (sys_clk ) ,
. sys_rst_n (sys_rst_n ) ,
. led (led ) );
always#19 sys_clk=~sys_clk;
initial begin
sys_clk=1'b0;
sys_rst_n=1'b0;
#50
sys_rst_n=1'b1;
end
endmodule
六、上板验证
呼吸灯上板
七、问题分析
- 第一次做,我感觉效果不太好,灯亮暗得太快了,而且暗下去时感觉并没有完全暗下去,下次可以试试暗下去之后等个半秒钟再亮起来
- 代码中用了一个乘法器,个人感觉这一块还可以优化,最好不用乘法器,资源消耗太大了,我还没想到更好的方法,大家有懂的一起讨论。