FPGA呼吸灯
发布时间
阅读量:
阅读量
FPGA呼吸灯
- 关于呼吸灯:
- 占空比:
- 代码实现:
关于呼吸灯:
呼吸灯,就是像人们呼吸频率的一种led灯亮灭的一种表现形式。过程是慢慢变亮,然后变亮以后又慢慢变灭的一种过程。
占空比:
占空比是指在一个脉冲循环内,正脉冲序列的持续时间与脉冲总周期的比值。。占空比(Duty Ratio)在电信领域中有如下含义:例如:脉冲宽度1μs,信号周期4μs的脉冲序列占空比为0.25。
假设刚开始时占空比为1%,慢慢的占空比为2%、3%、4%……56%、57%……98%、99%、100%。
这就是LED灯亮的一个过程,我们可以让占空比为1%时,令LED灯亮,其余的部分让LED灭,慢慢的占空比越来越大,亮的部分也越来越多,这就是一个由灭到亮的一个过程。
假设刚开始时占空比为100%,慢慢的占空比为99%、98%、97%……64%、63%……2%、1%、0%。
这就是LED灯灭的一个过程,我们可以让占空比为99%时,令LED灯灭,其余的部分让LED亮,慢慢的占空比越来越小,灭的部分也越来越多,这就是一个由亮到灭的一个过程。
代码实现:
按键消抖模块key_debounce.v:
module key_debounce #(parameter KEY_W = 1,DELAY_TIME = 1000_000)(
input clk ,
input rst_n ,
input [KEY_W-1:0] key_in ,
output [KEY_W-1:0] key_out
);
//信号定义
reg [19:0] cnt ;//延时计数器
wire add_cnt ;
wire end_cnt ;
reg flag ;
reg [KEY_W-1:0] key_r0 ;//同步寄存器
reg [KEY_W-1:0] key_r1 ;//打拍寄存器
wire [KEY_W-1:0] nedge ;//检测下降沿
reg [KEY_W-1:0] key_flag;//按键按下标志
//计数器
always @(posedge clk or negedge rst_n)begin
if(~rst_n)begin
cnt <= 0;
end
else if(add_cnt)begin
if(end_cnt)
cnt <= 0;
else
cnt <= cnt + 1;
end
end
assign add_cnt = flag;
assign end_cnt = add_cnt && cnt == DELAY_TIME-1;
always @(posedge clk or negedge rst_n)begin
if(~rst_n)begin
flag <= 1'b0;
end
else if(nedge != 0)begin
flag <= 1'b1;
end
else if(end_cnt)begin
flag <= 1'b0;
end
else begin
flag <= flag;
end
end
//同步 打拍
always @(posedge clk or negedge rst_n)begin
if(~rst_n)begin
key_r0 <= {KEY_W{1'b1}};
key_r1 <= {KEY_W{1'b1}};
end
else begin
key_r0 <= key_in;//同步
key_r1 <= key_r0;//打拍
end
end
//assign nedge = key_r1 == 1'b1 && key_r0 == 1'b0; //一位按键
//assign nedge = {key_r1[0] == 1 && key_r0[0] == 0,key_r1[1] == 1 && key_r0[1] == 0};
//assign nedge = {key_r1[0] && ~key_r0[0],key_r1[1] && ~key_r0[1]};
assign nedge = key_r1 & ~key_r0;
//输出寄存器key_flag
always @(posedge clk or negedge rst_n)begin
if(~rst_n)begin
key_flag <= 0;
end
else begin
key_flag <= end_cnt ?~key_r1:0;
end
end
assign key_out = key_flag;
endmodule
AI写代码
呼吸灯模块led_ctrl.v:
module led_ctrl (
input clk ,
input rst_n ,
input [1:0] mod_sel ,
output [3:0] led
);
//时间参数定义
parameter TIME_100MS = 5_000,
TIME_300MS = 15_000;
//信号定义
reg [13:0] cnt0 ;//基准定时 T = 100us/300us
wire add_cnt0 ;
wire end_cnt0 ;
reg [13:0] X ;
reg [6:0] cnt1 ;//100个基准时间 计10ms或30ms
wire add_cnt1 ;
wire end_cnt1 ;
reg [6:0] cnt2 ;//100个10ms、30ms 1S / 3S
wire add_cnt2 ;
wire end_cnt2 ;
reg dir_flag ;//方向寄存器
reg mode_flag ;//模式标志
reg [1:0] sel_flag ;//模式选择寄存
reg [3:0] led_r ;//输出寄存器
//计数器
always @(posedge clk or negedge rst_n) begin //计数 T 10ms / 30ms
if (rst_n==0) begin
cnt0 <= 0;
end
else if(add_cnt0) begin
if(end_cnt0)
cnt0 <= 0;
else
cnt0 <= cnt0+1 ;
end
end
assign add_cnt0 = 1'b1;
assign end_cnt0 = add_cnt0 && cnt0 == X-1 ;
always @(*)begin
if(mode_flag == 0)begin
X = TIME_100MS;
end
else begin
X = TIME_300MS;
end
end
always @(posedge clk or negedge rst_n) begin //计数 100 个 T 100us / 300us
if (rst_n==0) begin
cnt1 <= 0;
end
else if(add_cnt1) begin
if(end_cnt1)
cnt1 <= 0;
else
cnt1 <= cnt1+1 ;
end
end
assign add_cnt1 = end_cnt0;
assign end_cnt1 = add_cnt1 && cnt1 == 100-1;
always @(posedge clk or negedge rst_n) begin //计数 100 个 100*T 1s / 3s
if (rst_n==0) begin
cnt2 <= 0;
end
else if(add_cnt2) begin
if(end_cnt2)
cnt2 <= 0;
else
cnt2 <= cnt2+1 ;
end
end
assign add_cnt2 = end_cnt1;
assign end_cnt2 = add_cnt2 && cnt2 == 100-1 ;
always @(posedge clk or negedge rst_n)begin
if(~rst_n)begin
dir_flag <= 1'b0;
end
else if(end_cnt2)begin
dir_flag <= ~dir_flag;
end
end
always @(posedge clk or negedge rst_n)begin
if(~rst_n)begin
led_r <= 4'b0000;
end
else if(dir_flag == 1'b0 && cnt1 <= cnt2)begin
led_r <= 4'b1111;
end
else if(dir_flag && cnt1 <= 99-cnt2)begin
led_r <= 4'b1111;
end
else begin
led_r <= 4'b0000;
end
end
//mode_flag 一轮结束后才切换模式
always @(posedge clk or negedge rst_n)begin
if(~rst_n)begin
mode_flag <= 1'b0;
end
else if(dir_flag && end_cnt2 && sel_flag[1])begin
mode_flag <= 1'b1;
end
else if(dir_flag && end_cnt2 && sel_flag[0])begin
mode_flag <= 1'b0;
end
end
always @(posedge clk or negedge rst_n)begin
if(~rst_n)begin
sel_flag <= 0;
end
else if(dir_flag && end_cnt2 && sel_flag != 0)begin
sel_flag <= 0;
end
else if(mod_sel != 0)begin
sel_flag <= mod_sel;
end
end
assign led = led_r;
endmodule
AI写代码
顶层代码breath_led:
module breath_led(
input clk ,
input rst_n ,
input [1:0] key_in ,
output [3:0] led_out
);
//信号定义
wire [1:0] key_flag ;
//模块例化
//按键消抖
key_debounce #(.KEY_W(2))u_key(
/*input */.clk (clk ),
/*input */.rst_n (rst_n ),
/*input [1:0] */.key_in (key_in ),
/*output [1:0] */.key_out (key_flag )
);
led_ctrl u_led(
/*input */.clk (clk ),
/*input */.rst_n (rst_n ),
/*input [1:0] */.mod_sel (key_flag ),
/*output [3:0] */.led (led_out )
);
endmodule
AI写代码
仿真代码breath_led_tb.v:
`timescale 1 ns/1 ns
module breath_led_tb();
reg clk ;
reg rst_n ;
reg [1:0] key_in;
wire [3:0] led_out ;
parameter CYCLE = 20;
parameter RST_TIME = 3 ;
breath_led u_breath_led(
/*input */.clk (clk ),
/*input */.rst_n (rst_n ),
/*input [1:0] */.key_in (key_in ),
/*output [3:0] */.led_out (led_out)
);
defparam u_breath_led.u_key.DELAY_TIME = 10,
u_breath_led.u_led.TIME_100MS = 2,
u_breath_led.u_led.TIME_300MS = 6;
initial begin
clk = 1;
forever
#(CYCLE/2)
clk=~clk;
end
initial begin
rst_n = 1;
#2;
rst_n = 0;
#(CYCLE*RST_TIME);
rst_n = 1;
end
initial begin
#1;
#(10*CYCLE);
key_in = 2'b11;
#(20*CYCLE); //模式1
key_in = 2'b01;
#(20*CYCLE);
key_in = 2'b11;
#(20000*CYCLE); //模式0
key_in = 2'b10;
#(20*CYCLE);
key_in = 2'b11;
#(20000*CYCLE);
$stop;
end
endmodule
AI写代码
仿真结果:

全部评论 (0)
还没有任何评论哟~
