FPGA学习笔记:verilog基础代码与modelsim仿真(四)——呼吸灯-FPGA常见问题社区-FPGA CPLD-ChipDebug

FPGA学习笔记:verilog基础代码与modelsim仿真(四)——呼吸灯

 

 

呼吸灯

功能目标:实现Led灯由熄灭逐渐变亮至完全点亮,再逐渐变暗至完全熄灭,循环往复。

 

1.输入输出原理图

在这里插入图片描述
将系统时钟与复位按键作为输入,led灯状态作为输出,直观显示最终结果。

2.波形图绘制(visio)

led灯波形图
首先根据实现目标明确led灯在熄灭->点亮->熄灭过程中的波形图,其中低电平代表点亮,高电平代表熄灭;在熄灭->点亮过程,想要实现“呼吸”效果,就需要在每个周期T内逐渐增加led灯的点亮时间,最终将各个周期合并,实现“呼吸”效果。

那么,有了点亮时的呼吸效果,熄灭的呼吸效果就是将熄灭、点亮时间反过来就可以实现了。
在这里插入图片描述

 

接下来,我们利用上文提到的时钟与复位按键,同时引入中间变量绘制完整的波形图:

由灭到亮:

实现由灭到亮的呼吸效果

由亮到灭:

在这里插入图片描述
sys_clk是频率为50Mhz的系统时钟;

sys_rst_n:复位按键,低电平有效,这里我们设除开始一小段时间外,按键始终处于高电平即无效状态;

cnt_1s:1s计数器 ; cnt_1ms : 1ms计数器:以此类推…

特定时间计数器的模值在其他文章里已经说明过,这里不再赘述。

cnt_en : 使能信号,这里的作用是判断led灯何时转换状态,例如上图,当led由亮逐渐熄灭时,当led完全熄灭,cnt_en则由高电平进入低电平,从而使led开始逐渐点亮。

led_out: led输出波形。

代码实现:

module breath_led
 #(
    parameter   CNT_1us_MAX = 6'd49 ,   //The maximum modulus of the counter
    parameter   CNT_1ms_MAX = 11'd999 ,
    parameter   CNT_1s_MAX = 11'd999 
    
 
 
 )
 (
    input   wire    sys_clk     ,
    input   wire    sys_rst_n   ,
    
    
    output  reg     led_out
   
    
 );
 
reg  [10:0]  cnt_1s;
reg  [10:0]  cnt_1ms;
reg  [5:0]  cnt_1us;
reg          cnt_en ;

always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_1us <= 6'd0;
    else if(cnt_1us == CNT_1us_MAX)
        cnt_1us <= 6'd0;
    else
        cnt_1us <= 6'd1 + cnt_1us ;
        
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_1ms <= 11'd0;
    else if(cnt_1us == CNT_1us_MAX && cnt_1ms == CNT_1ms_MAX)
        cnt_1ms <= 11'd0;
    else if(cnt_1us == CNT_1us_MAX)
        cnt_1ms <= 11'd1 + cnt_1ms ;
    else
          cnt_1ms <=  cnt_1ms ;
          
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_1s <= 11'd0;
    else if(cnt_1ms == CNT_1ms_MAX && 
            cnt_1s == CNT_1s_MAX && cnt_1us == CNT_1us_MAX )
        cnt_1s <= 11'd0;
    else if(cnt_1ms == CNT_1ms_MAX && cnt_1us == CNT_1us_MAX)
        cnt_1s <= 11'd1 + cnt_1s ;
    else
          cnt_1s <=  cnt_1s ;
          
          
          
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_en <= 1'd0;
    else if((cnt_1us == CNT_1us_MAX) && (cnt_1ms == CNT_1ms_MAX) 
            && (cnt_1s == CNT_1s_MAX) )
        cnt_en <= ~cnt_en;
    
    else
          cnt_en <=  cnt_en ;  

          
          
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        led_out <= 1'b1 ;
    else if(((cnt_en == 1'b0) && (cnt_1ms <= cnt_1s)) 
            || ((cnt_en == 1'b1)&& (cnt_1ms > cnt_1s)))
        led_out<= 1'b1 ;
 
    else
        led_out <= 1'b0;
          
          
          

  
 endmodule

 

实例化文件:

`timescale 1ns/1ns
   module tb_breath_led();
   
   reg sys_clk;
   reg sys_rst_n;
   wire led_out;
   
  
   initial
      begin
          sys_clk = 1'b1;
          sys_rst_n <= 1'b0;
          #20
          sys_rst_n <= 1'b1;
      end
   
   
   /*initial 
      begin
          $timeformat(-9,0,"ns",6);
          $monitor("@time %t :in_1=%b,in_2=%b,cin=%b,sum=%b,count=%b" ,$time,in_1,in_2,cin,sum,count);
      end*/
      
      
  always #10 sys_clk = ~sys_clk; //clk frequency
 
  
 breath_led 
  #(
        
        .CNT_1us_MAX (7'd100),
        .CNT_1ms_MAX (10'd500),
        .CNT_1s_MAX  (10'd500)
                  
  
  )
 breath_led_inst
  (
          .sys_clk  (sys_clk)   ,
          .sys_rst_n(sys_rst_n)   ,
          .led_out (led_out) 
     
             
          
  );
      
  endmodule

 

请登录后发表评论

    没有回复内容