一、原理讲解
1、功能实现
利用led灯实现简易呼吸灯,在2s内由亮变暗,在另外一个2s内由暗变亮。
led灯呼吸效果是由时钟周期内高低电平的时长不同所导致的,也即占空比不同。相同时钟周期内, 占空比50%的LED灯亮度高于占空比为40%的LED灯亮度。
2、设计思路
利用三个计数器cnt_2s、cnt_2ms、cnt_2us这三个计数器,利用计数器cnt_2ms与cnt_2s的大小比较,进行占空比的改变,当cnt_2ms计数器计满时,计数器cnt_2s加1,计数器cnt_2ms则清零。利用flag标志信号作为2s计数计满标志,当flag为0且计满2s后,led灯有亮变暗;当flag为1且计满2s后,led由暗变亮,从而实现led的亮暗变换过程。
二、源码
有关工程创建的相关步骤详解可参考博客;
【FPGA实战篇四】数码管实现秒表计数
breath_led.v
module breath_led(
input clk ,//系统时钟(50Mhz)
input rst_n ,//复位信号(低电平有效)
output reg[3:0] led //输出led灯状态
);
//参数定义
parameter TIME_2S = 1000 ,
TIME_2MS = 1000 ,
TIME_2US = 50 ;
//信号定义
reg [9:0] cnt_2s ;//秒计数器
wire add_cnt_2s ;
wire end_cnt_2s ;
reg [9:0] cnt_2ms ;//毫秒计数器
wire add_cnt_2ms ;
wire end_cnt_2ms ;
reg [5:0] cnt_2us ;//微秒计数器
wire add_cnt_2us ;
wire end_cnt_2us ;
reg flag;//计数到两秒,状态翻转标志信号
//2微秒计数器
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
cnt_2us <= 0;
end
else if(add_cnt_2us)begin
if(end_cnt_2us)begin
cnt_2us <= 0;
end
else begin
cnt_2us <= cnt_2us + 1;
end
end
end
assign add_cnt_2us = 1'b1;
assign end_cnt_2us = add_cnt_2us && cnt_2us == TIME_2US - 1;
//2毫秒计数器
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
cnt_2ms <= 0;
end
else if(add_cnt_2ms)begin
if(end_cnt_2ms)begin
cnt_2ms <= 0;
end
else begin
cnt_2ms <= cnt_2ms + 1;
end
end
end
assign add_cnt_2ms = end_cnt_2us;
assign end_cnt_2ms = add_cnt_2ms && cnt_2ms == TIME_2MS - 1;
//2s计数器
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
cnt_2s <= 0;
end
else if(add_cnt_2s)begin
if(end_cnt_2s)begin
cnt_2s <= 0;
end
else begin
cnt_2s <= cnt_2s + 1;
end
end
end
assign add_cnt_2s = end_cnt_2ms;
assign end_cnt_2s = add_cnt_2s && cnt_2s == TIME_2S - 1;
//计数2s,flag翻转
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
flag <= 0;
end
else if((flag == 0) && end_cnt_2s)begin
flag <= 1'b1;
end
else if((flag == 1) && end_cnt_2s)begin
flag <= 1'b0;
end
end
//led状态变化
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
led <= 4'b0000;
end
else if(((flag == 1'b0) && cnt_2ms < cnt_2s) || ((flag == 1'b1) && cnt_2ms > cnt_2s))begin
led <= 4'b1111;
end
else begin
led <= 4'b0000;
end
end
endmodule
breath_led_tb.v
`timescale 1ns/1ns
module breath_led_tb();
reg clk ;
reg rst_n ;
wire [3:0] led ;
//模块例化
breath_led u_breath_tb(
.clk (clk ),
.rst_n (rst_n),
.led (led )
);
//定义时钟周期
parameter CLOCK_CYCLE = 20;
//产生激励信号
initial clk = 1'b0;
always #(CLOCK_CYCLE/2) clk = ~clk;
initial begin
rst_n = 1'b0;
#(CLOCK_CYCLE*20);
rst_n = 1'b1;
#(CLOCK_CYCLE*100_000_000);
$stop;
end
endmodule