点灯大师(2)led呼吸灯
上一章学习了流水灯跑马灯,接下来学习如何编写呼吸灯。
前言
呼吸灯的应用非常广泛,一些手机充电时顶上一亮一亮的就是呼吸灯。简单来说呼吸灯就是模仿人类呼吸的动作,吸入呼出,变为由亮变暗,由暗变亮。
一、呼吸灯原理
呼吸灯就是利用PWM(脉冲宽度调制)的原理,不了解PWM没关系,简单来说,就是调节led灯的亮和灭在一定时间内的占比,一般一个led的正常亮灭的占比是各50%,但如果我调节亮灭占比,比如我给亮占比20%,给灭占比80%,就是比正常的led暗一点,反之就是比正常的亮一点,所以我们设计的思路就是控制这个占空比。
在由计数器产生的固定周期的 PWM 信号下,如果其占空比为 0,则 LED 灯不亮;如果其占空比为100%,则 LED 灯最亮。所以将占空比从 0 到 100%,再从 100%到 0 不断变化,就可以实现 LED 灯的“呼吸”效果。
二、代码
1.呼吸灯
代码如下
/*
* @Projcet: breathe_led
* @Author: Yang.
* @Date: 2023-09-30 08:48:22
* @LastEditors: Yang.
* @LastEditTime: 2023-09-30 19:38:59
*/
//---------<模块及端口声名>------------------------------------------------------
module breathe_led(
input wire clk ,
input wire rst_n ,
output reg [3:0] led_out
);
//---------<参数定义>---------------------------------------------------------
parameter TIME_2US = 6'd99 ;
parameter TIME_2MS = 10'd999 ;
parameter TIME_2S = 10'd999;
reg [6:0] cnt_2us;//0-99需要7位
wire add_cnt_2us ;
wire end_cnt_2us ;
reg [9:0] cnt_2ms;//0-999需要10位
wire add_cnt_2ms ;
wire end_cnt_2ms ;
reg [9:0] cnt_2s ;//0-999需要10位
wire add_cnt_2s ;
wire end_cnt_2s ;
reg flag ;//FLAG LED亮灭的标志
//****************************************************************
//2us计数器
//****************************************************************
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
cnt_2us <= 'b0;
end
else if(add_cnt_2us)begin
if(cnt_2us == TIME_2US)begin
cnt_2us <= 'b0;
end
else begin
cnt_2us <= cnt_2us + 1'b1;
end
end
end
assign add_cnt_2us = 'd1;
assign end_cnt_2us = add_cnt_2us && cnt_2us == TIME_2US ;
//****************************************************************
//20ms计数器
//****************************************************************
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
cnt_2ms <= 10'b0;
end
else if(add_cnt_2ms)begin
if(end_cnt_2ms)begin
cnt_2ms <= 10'b0;
end
else begin
cnt_2ms <= cnt_2ms + 1'b1;
end
end
end
assign add_cnt_2ms = end_cnt_2us;
assign end_cnt_2ms = add_cnt_2ms && cnt_2ms == TIME_2MS ;
//****************************************************************
//2s计数器
//****************************************************************
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
cnt_2s <= 10'b0;
end
else if(add_cnt_2s)begin
if(end_cnt_2s)begin
cnt_2s <= 10'b0;
end
else begin
cnt_2s <= cnt_2s + 1'b1;
end
end
end
assign add_cnt_2s = end_cnt_2ms;
assign end_cnt_2s = add_cnt_2s && cnt_2s == TIME_2S ;
//****************************************************************
flag计数器标志信号
//****************************************************************
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
flag <= 1'b0;
end
else if(end_cnt_2s)begin
flag <= ~flag;
end
end
//****************************************************************
led:负责呼吸灯控制
//****************************************************************
always@(posedge clk or negedge rst_n) begin
if(!rst_n)begin
led_out <= 4'b0000;
end
else if (flag) begin
led_out <= (cnt_2s > cnt_2ms) ? 4'b1111 :4'b0000 ;
end
else begin
led_out <= (cnt_2s > cnt_2ms) ? 4'b0000 : 4'b1111 ;
end
end
endmodule
2.仿真
代码如下:
`timescale 1ns/1ns
module tb_led();
reg clk;
reg rst_n;
wire [3:0] led_out;
breathe_led u_breathe_led (
.clk (clk),
.rst_n (rst_n),
.led_out (led_out)
);
defparam u_breathe_led.TIME_2S = 10;
defparam u_breathe_led.TIME_2MS= 10;
defparam u_breathe_led.TIME_2US= 5;
always #5 clk = ~clk;
initial begin
clk = 0;
rst_n = 0;
#10
rst_n = 1;
end
endmodule
总结
1、仿真结果
从仿真中可以看出led灯珠亮(1111)的时间越来越短一个周期,也就是越来越暗。
2、上板结果
点灯大师(2)---led呼吸灯
其实呼吸灯没什么可以大写特写的东西,占空比调解而已。
led玩出来的花样差不多了。
手里还有一个8*8的WS2812B的led灯板,不过那个现在发还太早,等再往深学几天再发啊。
博客上传的工程都在百度网盘,有压缩包也有整个文件,可以自行下载。
链接:https://pan.baidu.com/s/1lQqqWZXfb3i6XHwkKf52zg
提取码:yang
接下来数码管、蜂鸣器、按键消抖陆续就接上了,加油!!!!!