一、呼吸灯的原理
呼吸灯,顾名思义,就是跟人的呼吸一样,是有一个过程的,由暗到亮,再由亮到暗的过程。 关于呼吸灯的原理就是利用PWM(脉冲宽度调制)的原理,不了解PWM没关系,用一句通俗易懂的话,来说,就是调节led灯的亮和灭在一定时间内的占比,一般一个led的正常亮灭的占比是各50%,但如果我调节亮灭占比,比如我给亮占比20%,给灭占比80%,就是比正常的led暗一点,反之就是比正常的亮一点,所以我们设计的思路就是控制这个占空比
二、设计思路
可以结合第四部分的波形图来设计 我们这里使用的简单的版本思路,不是常规的定义三个计数器1s,1ms,1us,而是利用和单片机一样的的预装载值和预比较值的思路。 这里有几个变量和常量,我解释一下 常量
- PRE是预装载值,相当于led亮暗的一次。
- ADD_DATA是预比较值的累加值,相当于你需要让led逐渐变亮,所需要的占空比也越来越大。
变量
- compare是预比较值,相当于占空比。
- flag是led变亮变暗的标志符,逐渐变亮记一次flag,然后达到最大占空比,此时led最亮了,需要开始变暗,就将flag反转。
led逐渐变亮,说明占空比是逐渐变大的,计数器累加到亮灭的一次,也就是预装载值,占空比累加,计数器与预比较值相比较,如果当前正好是逐渐变亮而且计数小于预比较值,就给高电平,让小灯亮,其余的就给低电平,相当于说亮少,暗多,逐渐变得亮多,暗少。 用一个大饼来比喻,大饼来分,我们自己来分配这个分的比例。
三、代码部分
工程创建的部分在我之前的博客里 【FPGA】实战之创建项目
这里直接上代码!
module breath_led #(parameter PRE = 100000,parameter ADD_DATA = 100)(
input clk,
input rst_n,
output reg [3:0] led
);
//预装载值
// parameter PRE = 8000;
// 1000000计数器位宽20
reg [19:0] cnt;
wire add_cnt;
wire end_cnt;
//预比较值
reg [20:0] compare;
// 从暗到亮和从亮到暗的标志信号flag
// 从暗到亮flag=1,从亮到暗flga=0
reg flag;
// 计数器模块
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
cnt<=20'b0;
end
else if(add_cnt)begin
if(end_cnt)begin
cnt<=20'b0;
end
else begin
cnt<=cnt+1'b1;
end
end
else begin
cnt<=cnt;
end
end
assign add_cnt=1'b1;
assign end_cnt=add_cnt&&cnt==PRE-1;
//预比较值模块
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
compare<=0;
end
else if(compare>=PRE)begin
compare<=0;
end
else if(end_cnt)begin
compare<=compare+ADD_DATA;
end
else begin
compare<=compare;
end
end
//亮灭标志符flag模块
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
flag<=1'b0;
end
else if(compare>=PRE)begin
flag=~flag;
end
else begin
flag<=flag;
end
end
//通过flag标志符以及计数器和预比较值的比较来控制呼吸灯模块
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
led<=4'b0000;
end
// 如果是从暗到亮并且计数器小于预比较值 ,逐渐变亮
else if((flag==1'b0&&cnt<compare)||(flag==1'b1&&cnt>compare))begin
led<=4'b1111;
end
else begin
led<=4'b0000;
end
end
endmodule
四、仿真验证
1.这段就是由暗到亮的波形图,可以看到高电平的占比是越来越大的 2.这段就是由亮到暗的波形图,可以看到高电平的占比是越来越小的
五、上板烧录验证
没问题
|