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이 나오는 문제점이 존재하지만 후에 진도를 나가면서 진행할 예정