FPGA基础入门篇(九)使用 Verilog 实现 LED 呼吸灯效果
FPGA基础入门篇(九)使用 Verilog 实现 LED 呼吸灯效果呼吸灯为常见的数字IC设计案例,也比较简单,主要是关于呼吸灯的原理需要理解。常见的应用在手机的呼吸灯,这里我们采用硬件描述语言来实现LED呼吸灯的效果,即在1s内,LED灯由暗逐渐变亮,再1s内再由亮逐渐变暗。一、设计原理呼吸灯设计原理归结为对于分频和占空比的应用,就是先分频,然后再设置占空比的设计。占空比也就是控制LED...
FPGA基础入门篇(九)使用 Verilog 实现 LED 呼吸灯效果
呼吸灯为常见的数字IC设计案例,也比较简单,主要是关于呼吸灯的原理需要理解。常见的应用在手机的呼吸灯,这里我们采用硬件描述语言来实现LED呼吸灯的效果,即在1s内,LED灯由暗逐渐变亮,再1s内再由亮逐渐变暗。
一、设计原理
呼吸灯设计原理归结为对于分频和占空比的应用,就是先分频,然后再设置占空比的设计。占空比也就是控制LED暗亮的时间达到具有呼吸灯的效果。
首先要引入 脉冲宽度调制(PWM) 的概念,LED的点亮和熄灭,是电平高低变换的结果,可以将一高一低看作一个周期,每个周期一亮一灭,会显示为LED的闪烁,当周期很短,也就是频率很高时,这种闪烁将不被肉眼识别,会让人产生LED连续发光的感觉。在一个周期内,高电平时长与一个周期时长的比叫做占空比,占空比越高,相当于通过LED的电流就越大,视觉上的感觉就越亮。说到这里,应该就有了做呼吸灯的思路,就是改变占空比!让占空比小幅度有级提升,就会有LED无级变亮的感觉。反之就会变暗。占空比越高,亮度越亮。
首先将1s 分为1000份(1ms),然后在1ms内在继续分为1000份(1us),每一个1ms内,依次增加亮灯时间
即:
第1个1ms内亮灯1us
第2个1ms内亮灯2us
第3个1ms内亮灯2us
… …
第1000个1ms内亮灯1000us
二、基于Verilog设计
module led_breath(
input clk_i, //100MHz
input rst_n_i,
output led_o
);
//1s计数器
reg flag_1s;
reg [26:0] cnt_1s;
always @(posedge clk_i)
begin
if (! rst_n_i)begin
cnt_1s <= 27'b0;
flag_1s <= 1'b0;
end
else if(cnt_1s == 27'd100_000_000 ) begin
cnt_1s <= 27'b0;
flag_1s <= 1'b1;
end
else begin
cnt_1s <= cnt_1s + 1'b1;
flag_1s <= 1'b0;
end
end
//1ms计数器
reg flag_1ms;
reg [17:0] cnt_1ms;
always @(posedge clk_i)
begin
if (! rst_n_i)begin
cnt_1ms <= 18'b0;
flag_1ms <= 1'b0;
end
else if(cnt_1ms == 18'd100_000 ) begin
cnt_1ms <= 18'b0;
flag_1ms <= 1'b1;
end
else begin
cnt_1ms <= cnt_1ms + 1'b1;
flag_1ms <= 1'b0;
end
end
//1us计数器
reg flag_1us;
reg [6:0] cnt_1us;
always @(posedge clk_i)
begin
if (! rst_n_i)begin
cnt_1us <= 7'b0;
flag_1us <= 1'b0;
end
else if(cnt_1us == 7'd100) begin
cnt_1us <= 7'b0;
flag_1us <= 1'b1;
end
else begin
cnt_1us <= cnt_1us + 1'b1;
flag_1us <= 1'b0;
end
end
//计数多少个ms
reg [9:0] number_ms;
always @(posedge clk_i)
begin
if (! rst_n_i )begin
number_ms <= 10'd0;
end
else begin
if(number_ms == 10'd1000)begin
number_ms <= 10'd0;
end
else if(flag_1ms == 1'b1) begin
number_ms <= number_ms + 1'b1;
end
else begin
number_ms <= number_ms;
end
end
end
//计数多少个us
reg [9:0] number_us;
always @(posedge clk_i or negedge rst_n_i)
begin
if (! rst_n_i )begin
number_us <= 10'd0;
end
else begin
if(number_us == 10'd1000)begin
number_us <= 10'd0;
end
else if(flag_1us == 1'b1) begin
number_us <= number_us + 1'b1;
end
else begin
number_us <= number_us;
end
end
end
//module of led breath
//
wire led_flag0; //由暗逐渐变亮
wire led_flag1; //由亮逐渐变暗
assign led_flag0 = (number_ms > number_us)? 1: 0;
assign led_flag1 = (number_ms > number_us)? 0: 1;
assign led_o = (led_flag)? led_flag0 : led_flag1;
reg led_flag; //每隔1s 翻转一次信号
always @(posedge clk_i or negedge rst_n_i)
begin
if (! rst_n_i)begin
led_flag <= 1'b1;
end
else if (flag_1s == 1'b1) begin
led_flag <= ~ led_flag;
end
else begin
led_flag <= led_flag;
end
end
endmodule
仿真结果

当复位信号复位时,ms和us计数器均开始计数.
1us,1ms的时间均通过计数器来控制
每过1us,us计数器累加(number_us),一直到1ms累加到1000us即计数清零。
每过1ms,ms计数器累加(number_ms),一直到1ms累加到1000ms即计数清零。
当 number_us < number_ms,led_flag被拉高成高电平。这样在1s内,有1000次 led_flag 被拉高的,并且每次时间间隔一次增加。(0到999)
经过上板验证,确实可以实现LED灯有呼吸效果。
关于使用C语言程序来控制GPIO实现LED呼吸灯的效果可以参考下面一篇博文,主要介绍使用ZYNQ PS部分来实现。
更多推荐


所有评论(0)