Verilog implements breathing running water lamp

1. Design purpose
Realize a breathing running water lamp that changes from dark to bright within 1 second, and then from bright to dark again in the next 1 second.
2. Design ideas
Design a square wave with a gradually increasing duty cycle to change from dark to bright; then the duty cycle gradually becomes smaller to achieve a change from bright to dark. After each LED light completes this operation, it switches to the next LED to achieve the flowing water effect.
3. Overview of implementation logic
First, it is assumed that the reduction rate of the duty cycle is 0.1%, so 1s is first divided into 1000 ms, and the difference in duty cycle between each ms is 0.1.
In each 1ms, we obviously want to implement a square wave with a specified duty cycle, so we set a counter to start counting from 0. For example, in the first 1ms, we want the duty cycle to be 0, and the LED will be 0 in the entire 1ms. High level, the duty cycle is 99.9% in the second 1ms (low level duration accounts for 0.1%), so we pull the LED low when the counter is less than 1, and then pull it high; in the third 1ms, the counter is less than 3 When pulled low, and so on, we can find that each time the comparison object of count grows from 0 to 1000, it can exactly correspond to the ms where our counter is at this time, so we can directly compare the values of the two counters. To determine whether the LED is at a low level or a high level.
In addition, in order to facilitate observation, we hope that within each 1ms, the square wave with the specified duty cycle can be maintained slightly for easier observation, so we designed an intermediate counter count_us. Since the clock cycle is 10ns, and we have divided 1s into 1000ms before, we will do the following processing of 1ms. Looking from the bottom up, we mentioned before that the duty cycle is determined by comparing the count with the number of 1ms, so The threshold of count corresponds to 1000. In this way, it takes 100010, that is, 10000ns, to obtain a square wave with a specified duty cycle. It has been divided into 1000 parts of 1ms before, so we can make the square wave with a specified duty cycle Repeat 1s/100010000ns=100 times within this 1ms to meet the design requirements and facilitate observation.
So we set the three counters as count_ms, count_us, and count_num in sequence, which respectively indicate the current 1ms, the current 1ms square wave, and the current square wave count value.
Summarized as follows:

Each of the 100 cycles within 1ms is the same, and the specified square waveform is repeated 100 times.
4. Implementation code
(1) Design documents

module breathe
  #(
  parameter TIME_US = 100,
  parameter TIME_MS = 1000,
  parameter NUMBER = 1000
  )

  (
  input sys_clk_p,
  input sys_clk_n,
  input rst_n,
  output reg [7:0] led
  );


  wire enable;
  reg enable_reg;
  always@(posedge clk or negedge rst_n)
  begin
    if(~rst_n)begin
      enable_reg<=0;
    end
    else
      enable_reg <= enable;
  end

  reg [9:0] count_phase; //When the count reaches 1us, it returns to 0 every time it reaches 1us.
  reg [9:0] count_us; //The unit is 1us, and it returns to 0 when the count reaches 1ms.
  reg [9:0] count_ms; //The unit is 1ms, and the count returns to 0 when it reaches 1s.

  //Time to 1us
  always @(posedge clk or negedge rst_n) begin
    if(~rst_n) begin
      count_phase <= 0;
    end else if(count_phase == NUMBER - 1)begin
      count_phase <= 0 ;
    end
    else if(enable)
      count_phase <= count_phase + 1;
  end

  //Time to 1ms
  always @(posedge clk or negedge rst_n) begin
    if(~rst_n) begin
      count_us <= 0;
    end else if(count_us== TIME_US - 1 & amp; & amp; count_phase == NUMBER - 1)begin //Return to 0 every time 1000 us is counted, and then start a new round of duty cycle
      count_us <= 0;
    end
    else if(count_phase == NUMBER - 1)
      count_us <= count_us + 1;
  end


  reg flag_1s = 0;
  //Time to 1s
  always@(posedge clk or negedge rst_n)
  begin
    if(~rst_n)
      count_ms <= 0;
    else if(count_ms == TIME_MS & amp; & amp; ~flag_1s & amp; & amp; count_us == TIME_US - 1 & amp; & amp; count_phase == NUMBER - 1)
    begin
      count_ms <= count_ms - 1;
      flag_1s <= 1;
    end
    else if(count_ms == 0 & amp; & amp; flag_1s & amp; & amp; count_us == TIME_US - 1 & amp; & amp; count_phase == NUMBER - 1)
    begin
      count_ms <= count_ms + 1;
      flag_1s <= 0;
    end
    else if(count_us == TIME_US - 1 & amp; & amp; ~flag_1s & amp; & amp; count_phase == NUMBER - 1)
      count_ms <= count_ms + 1;
    else if(count_us == TIME_US - 1 & amp; & amp; flag_1s & amp; & amp; count_phase == NUMBER - 1)
      count_ms <= count_ms - 1;
  end

  reg flag_1s_reg;
  wire flag_neg;
  assign led_on = (count_phase < count_ms & amp; & amp; enable)? 0:1;

  always @(posedge clk or negedge rst_n) begin
    if(~rst_n) begin
      flag_1s_reg <= 0;
    end else begin
      flag_1s_reg <= flag_1s;
    end
  end

  assign flag_neg = flag_1s_reg & amp; ~flag_1s;

  reg [2:0]count_num;
  always@(posedge clk or negedge rst_n)
  begin
    if(!rst_n)
      count_num<=0;
    else if(flag_neg)
      count_num <= count_num + 1;
  end

  always@(posedge clk or negedge rst_n)
  begin
    if(!rst_n)
    begin
      led<=8'hff;
    end
    else case(count_num)
      3'b000 : led <= {led_on,7'b1111111};
      3'b001 : led <= {1'b1,led_on,6'b111111};
      3'b010 : led <= {2'b11,led_on,5'b11111};
      3'b011 : led <= {3'b111,led_on,4'b1111};
      3'b100 : led <= {4'b1111,led_on,3'b111};
      3'b101 : led <= {5'b11111,led_on,2'b11};
      3'b110 : led <= {6'b111111,led_on,1'b1};
      3'b111 : led <= {7'b1111111,led_on};
    endcase
  end

    clk_wiz_0 clock_gen
   (
    // Clock out ports
    .clk_out1(clk), // 50MHz
    .clk_out2(clk_out2), //25MHz
    // Status and control signals
    .resetn(rst_n), // input resetn
    .locked(enable), // output locked
   // Clock in ports
    .clk_in1_p(sys_clk_p), // input clk_in1_p
    .clk_in1_n(sys_clk_n)
    );

endmodule

(2) Simulation incentives

module tb_breathe ();
  reg clk_in;
  reg rst_n;
  wire sys_clk_p = clk_in;
  wire sys_clk_n = ~clk_in;
  wire led_0;
  wire led_1;
  wire led_2;
  wire led_3;
  wire led_4;
  wire led_5;
  wire led_6;
  wire led_7;

always #5 clk_in = ~clk_in;

initial begin
    clk_in = 0;
    rst_n = 0;
    #200 rst_n = 1;
end

  breathe #(
      .TIME_US(10),
      .TIME_MS(100),
      .NUMBER(100)
    ) inst_breathe (
      .sys_clk_p (sys_clk_p),
      .sys_clk_n (sys_clk_n),
      .rst_n (rst_n),
      .led_0 (led_0),
      .led_1 (led_1),
      .led_2 (led_2),
      .led_3 (led_3),
      .led_4 (led_4),
      .led_5 (led_5),
      .led_6 (led_6),
      .led_7 (led_7)
    );

endmodule

5. Simulation results
For the convenience of simulation, the thresholds we took were not taken according to the actual 1s, but were first divided into 100 parts, the duty cycle was changed according to 1%, and then one cycle was repeated 10 times, and the duration of one cycle was 100 *10=1000ns.

Observing the picture, you can see that the breathing effect is achieved.

As shown in the figure, the waveform with the same duty cycle is repeated for 10 cycles within 18ms.

Observing the figure, it can be found that the duty cycle gradually decreases, and the low-level duration gradually decreases within one cycle, until it is all low level, and then the duty cycle gradually increases, and the low-level duration gradually decreases within one cycle. Small.
The flag signal changes from 0 to 1, indicating that the process of the LED light changing from dark to bright is completed. Then it changes from bright to dark, and the low level duration decreases. The flag signal changes from 1 to 0, indicating that the light to dark process is completed.