카테고리 없음

Verilog UP/DOWN COUNTER

오버헤드프레스 2023. 4. 26. 11:27

 

module counter_up_down(
    input clk,
    input down,     //down이 1일 때는 down, down이 0일 때는 up카운터
    input reset_n,
    output reg [3:0] count_1 = 0,
    output reg [3:0] count_10 = 0,
    output reg dec_clk = 1
);
    always @(negedge clk or negedge reset_n)begin
        if(!reset_n)begin
            count_1 = 0;
            count_10 = 0;
        end
        else begin
            if(down)begin
                if(count_1 == 0)begin
                    count_1 = 9;
                    if(count_10 == 0)begin
                        count_10 = 5;
                        dec_clk = 0;
                    end
                    else begin
                        count_10 = count_10 - 1;
                    end
                    end
                else begin
                    count_1 = count_1 - 1;
                    dec_clk = 1;
                end
            end

            else begin 
                dec_clk = 1;
                if(count_1 >= 9)begin
                    count_1 = 0;
                    if(count_10 >= 5)  count_10 = 0;
                        else
                            count_10 = count_10 + 1;
                        end
                    else count_1 = count_1 + 1; 
                    end
                end
           end

endmodule

up/down counter를 위한 코드

 

simulation을 통해 잘 작동하는지 확인한다.

 

reset_n = 0일 때 count_1, count_10 이 0 출력

 

down = 1 일 때, down counter를 실행하는 모습 

down이 0일 때, up counter를 실행하는 모습

 

 

down = 1, clk = 1, reset_n = 1일 때, count_1 = 9, count_10 = 5일 때마다 0의 dec_clk을 발생시킨다.

 

 

UP/DOWN COUNTER

버튼을 활용해 up/down counter를 만들기

 

`timescale 1ns / 1ps

module cook_timer_top(
    input clk,
    input [3:0] btn,
    output [3:0] com_an,
    output [6:0] seg,
    output [3:0] led
    );
    
    wire reset_n;
    wire btn_down, btn_incsec, btn_incmin; 
    wire dec_clk;
    wire clk_up_down_sec;
    wire down;
    
    wire [3:0] sec [1:0]; //4bit중 2bit를 할당한다는 뜻 같음
    wire [3:0] min [1:0];  //module의 output으로 받는거니까 wire로 받아야함
    wire led_on;
    reg time_out;
    
    //time_out = |{sec[0], sec[1], min[0], min[1]}; //16bit
    
    assign reset_n = ~btn[2]; //btn은 눌러야하니까 반전시켜서
    //{ PACKAGE_PIN U18   IOSTANDARD LVCMOS33 } [get_ports {btn[2]}] 
    
    
    D_flip_flop_posedge dff_down (.D(btn[1]), .E(clk_msec), .Q(btn_down)); 
    //{ PACKAGE_PIN T18   IOSTANDARD LVCMOS33 } [get_ports btn[1]] 
    
    D_flip_flop_posedge dff_incsec (.D(btn[3]), .E(clk_msec), .Q(btn_incsec)); 
    //{ PACKAGE_PIN T17   IOSTANDARD LVCMOS33 } [get_ports {btn[3]}]
    
     D_flip_flop_posedge dff_incmin (.D(btn[0]), .E(clk_msec), .Q(btn_incmin)); 
    // { PACKAGE_PIN W19   IOSTANDARD LVCMOS33 } [get_ports {btn[0]}]
    
    
    clock_usec uCLK (.clk(clk), .reset_n(reset_n), .clk_usec(clk_usec));
    clock_msec mCLK (.clk_usec(clk_usec), .reset_n(reset_n), .clk_msec(clk_msec));
    clock_sec sCLK (.clk_msec(clk_msec), .reset_n(reset_n), .clk_sec(clk_sec));
    clock_min MCLK (.clk_sec(clk_sec), .reset_n(reset_n), .clk_min(clk_min));
    
    always @ (posedge clk)begin
        time_out = |{sec[0], sec[1], min[0], min[1]};
    end
    
    FND_4digit_switcher FND_4digit (
    .value_1(sec[0]),
    .value_10(sec[1]),
    .value_100(min[0]),
    .value_1000(min[1]),
    .clk(clk),
    .com_an(com_an),
    .seg(seg)
    ); 
    
     T_flip_flop_posedge tff_down (.T(1), .clk(btn_down), .reset_n(time_out), .preset_n(1), .Q(down)); //preset은 0에서 작동하니 1을 준다.

    //00분 00초가 되면 time_out = 리셋 되면서 up count로 바뀐다.
    not (btn_down_n, btn_down); //btn_down_n = up,
    not (btn_incsec_n, btn_incsec); 
    not (btn_incmin_n, btn_incmin); 
    and (any_btn, btn_down_n, btn_incsec_n, btn_incmin_n, reset_n);
    
    T_flip_flop tff_led (.T(1), .clk(time_out), .reset_n(any_btn), .preset_n(1), .Q(led_on)); 
    
    assign led[0] = led_on;
    
    mux_2_1 mux_sec(
    .D({clk_sec, btn_incsec}),
    .S(down),
    .F(clk_up_down_sec)
    );
    
 //   and (clk_down_sec, down, clk_sec); //down = 1일 때 1초 clk로 나옴
 //  and (clk_up_sec, ~down, btn_inc); //down이 0일 때, 즉, up일 때 btn_clk에 의해 clk_up_sec가 1출력 
 //  or (clk_up_down_sec, clk_down_sec, clk_down_sec);
    
    counter_up_down counter_sec (
    .clk(clk_up_down_sec),
    .down(down),     //down이 1일 때는 down, down이 0일 때는 up카운터
    .reset_n(reset_n),
    .count_1(sec[0]),
    .count_10(sec[1]),
    .dec_clk(dec_clk)
);


mux_2_1 mux_min(
    .D({dec_clk, btn_incmin}),  //59될 때 나오는 dec_clk를 사용해야함 
    .S(down),
    .F(clk_up_down_min)
    );
    
    
counter_up_down counter_min (
    .clk(clk_up_down_min),
    .down(down),     //down이 1일 때는 down, down이 0일 때는 up카운터
    .reset_n(reset_n),
    .count_1(min[0]),
    .count_10(min[1])
);
    
endmodule







module counter_up_down(
    input clk,
    input down,     //down이 1일 때는 down, down이 0일 때는 up카운터
    input reset_n,
    output reg [3:0] count_1 = 0,
    output reg [3:0] count_10 = 0,
    output reg dec_clk = 0
);
    always @(negedge clk or negedge reset_n)begin
        if(!reset_n)begin
            count_1 = 0;
            count_10 = 1;
        end
        else begin
            if(down)begin
                if(count_1 == 0)begin
                    count_1 = 9;
                    if(count_10 == 0)begin
                        count_10 = 5;
                        dec_clk = 0;
                    end
                    else begin
                        count_10 = count_10 - 1;
                    end
                    end
                else begin
                    count_1 = count_1 - 1;
                    if(~|{count_1, count_10}) dec_clk = 1;  //모든 값이 0이 되었을 때 dec_clk을 1만든다. 1에서 0되고 59될 때 edge발생
                end       // |(0001, 0101) 이면 0 | 0 | 0 | 1  |  0 | 1 | 0 | 1 각 비트를 전부 or하는 것 
            end

            else begin 
                dec_clk = 0;
                if(count_1 >= 9)begin
                    count_1 = 0;
                    if(count_10 >= 5)  count_10 = 0;
                        else
                            count_10 = count_10 + 1;
                        end
                    else count_1 = count_1 + 1; 
                    end
                end
           end

endmodule

reset btn을 누르면 1010이 출력되며, 0까지 됐을 때 0100이 나오는 문제점이 존재하지만 후에 진도를 나가면서 진행할 예정