【FPGA实战篇五】led实现简易呼吸灯

一、原理讲解

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

三、仿真及开发板验证

1、仿真波形

在这里插入图片描述

2、开发板验证

在这里插入图片描述

Guess you like

Origin blog.csdn.net/QWERTYzxw/article/details/120657656