基于fpga_EP4CE6F17C8实现的呼吸灯

前言

网上找资料时一般出现的是led灯1s从暗到亮,下一个1s从亮到暗,所以在此记录一篇2s的呼吸灯,也为日后自己复习提供一点帮助,结尾有源码。

实验手册(EP4CE6F17C8)

一、实验目的

四个LED灯2s从暗到亮,下一个2s从亮到暗,循环显示。

二、实验原理

理论原理

在fpga中,呼吸灯的实现是通过控制占空比的多少,输出两段,第一段:由暗到亮,占空比由0%到100%逐步递增,第二段:由亮到暗,占空比由100%到0%逐步递减

三、系统架构设计

请添加图片描述

  • 呼气和吸气,周期为4秒。考虑呼气的过程,就是让led灯要有亮灭的变化,从暗到亮,再从亮到暗。
  • 为了led的亮度变化比较流畅,也就是每隔2ms我们给led灯一个新的亮度,我们将2秒拆分为1000份的2ms,为了实现led灯亮度变化,每一份2ms波形的占空比都不能相同,且必须是连续增加或减小的。
  • 2ms的时间内,我们一共有1000个状态,每一个状态就是一个占空比时间为2us。所以我们需要三个计数器。最后利用后面两个计数器cnt_2ms和cnt_2s的大小进行比较,来改变一个时钟周期内的占空比。

四、模块说明

1.模块端口信号列表

端口信号信号类别信号名称信号作用
inputwireclk时钟信号
inputwirerst_n复位信号
outputregledled信号

2.状态转移图

请添加图片描述

3.时序图

请添加图片描述

该图是用time gen来画的

五、仿真波形图

请添加图片描述

  • 这部分是从暗到亮的仿真波形,在breath_led一行我们可以很明显的看到从一开始基本看不见1111,到后面1111的占空比逐步扩大。
    请添加图片描述

  • 这部分则是从亮到暗,breath_led一行,0000的占空比逐步扩大

六、引脚分配

请添加图片描述

七、代码实现

module breath_led (
    input   clk         , 
    input   rst_n       ,

    output reg [3:0] breath_led  
);

parameter MAX_2us = 10'd99 ;    //2us
//之所以2ms和2s都是999,这是因为这两个的开始信号我分别设置为cnt_2us的结束信号、cnt_2ms的结束信号
//记了1000次的us信号就等于2ms,2s也是这个道理
parameter MAX_2ms = 19'd999;    //2ms = 1000 * 2us
parameter MAX_2s  = 19'd999;    //2s  = 1000 * 2ms  

reg [9:0] cnt_2us;
reg [18:0] cnt_2ms;
reg [18:0] cnt_2s;
reg [1:0] flag;     //状态转变标志,判断是从暗到亮还是从亮到暗

wire add_cnt_2us;   //计数器开始信号
wire end_cnt_2us;   //计数器结束信号

wire add_cnt_2ms;   
wire end_cnt_2ms;   

wire add_cnt_2s;    
wire end_cnt_2s;    

always @(negedge rst_n or posedge clk) begin
    if (!rst_n) begin
        cnt_2us <= 6'd0;
    end
    else if (add_cnt_2us) begin
        if (end_cnt_2us) begin
            cnt_2us <= 6'd0;
        end
        else begin
            cnt_2us <= cnt_2us + 6'd1;
        end
    end
    else begin
        cnt_2us <= cnt_2us;
    end
end
    assign add_cnt_2us = 1'd1;
    assign end_cnt_2us = add_cnt_2us && cnt_2us == MAX_2us; 

always @(negedge rst_n or posedge clk) begin
    if (!rst_n) begin
        cnt_2ms <= 6'd0;
    end
    else if (add_cnt_2ms) begin
        if (end_cnt_2ms) begin
            cnt_2ms <= 6'd0;
        end
        else begin
            cnt_2ms <= cnt_2ms + 6'd1;
        end
    end
    else begin
        cnt_2ms <= cnt_2ms;
    end
end
    assign add_cnt_2ms = end_cnt_2us;
    assign end_cnt_2ms = add_cnt_2ms && cnt_2ms == MAX_2ms; 

always @(negedge rst_n or posedge clk) begin
    if (!rst_n) begin
        cnt_2s <= 6'd0;
    end
    else if (add_cnt_2s) begin
        if (end_cnt_2s) begin
            cnt_2s <= 6'd0;
        end
        else begin
            cnt_2s <= cnt_2s + 6'd1;
        end
    end
    else begin
        cnt_2s <= cnt_2s;
    end
end
    assign add_cnt_2s = end_cnt_2ms;
    assign end_cnt_2s = add_cnt_2s && cnt_2s == MAX_2s; 

//每隔两秒,信号翻转,进入下一状态
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        flag <= 1'b0;
    end 
    else if(end_cnt_2s)begin 
        flag <= ~flag;//1s取反
    end 
    else begin 
        flag <= flag;
    end 
end


always @(negedge rst_n or posedge clk) begin
    if (!rst_n) begin
        breath_led <= 4'b0000;
    end
    //状态一:从暗到亮
    else if (!flag)begin
        breath_led <= (cnt_2s > cnt_2ms)?4'b1111:4'b0000;
    end
    //状态二:从亮到暗
    else if (flag) begin
        breath_led <= (cnt_2s > cnt_2ms)?4'b0000:4'b1111;
    end
    else begin
        breath_led <= breath_led;
    end
end
endmodule

八、仿真代码

`timescale 1ns/1ns
module breath_led_tb ();
//激励信号
    reg clk;
    reg rst_n;
//响应信号
    wire  [3:0] breath_led;

parameter CYCLE = 20;
//完整代码中的计数时间长,故在此重新赋予短时的参数,以便观察结果
parameter MAX_2us = 10;
parameter MAX_2ms = 20;
parameter MAX_2s  = 20;

//产生时钟信号
always #(CYCLE/2) clk = ~clk;

//产生激励
initial begin
    clk = 1'b0;
    rst_n = 1'b0;
    #(CYCLE);
    rst_n = 1'b1;
    #(2*(MAX_2us)*(MAX_2ms)*(MAX_2s)*CYCLE);//检测一个大周期:从暗到亮,从亮到暗
    $stop;
end
//实例化
breath_led #(
    .MAX_2us(MAX_2us),
    .MAX_2ms(MAX_2ms),
    .MAX_2s(MAX_2s)
)
u_breath_led(
    .clk(clk),
    .rst_n(rst_n),
    .breath_led(breath_led)
);

endmodule

九、板级验证效果

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值