728x90
반응형
[Stop Watch]
📌 Minute count 구현
Minute clock 설계
clk_sec을 60번 카운트하면 1분
// min clock
module clock_min(
input clk, clk_sec, reset_p,
output clk_min
);
// 60개 카운트하면 1s
reg [5:0] cnt_sec;
reg cp_min; // cp : clock pulse
always @(posedge clk, posedge reset_p) begin
if(reset_p) cnt_sec = 0; // reset이 들어오면 cnt = 0
else if(clk_sec) begin
if (cnt_sec >= 29) begin
cnt_sec = 0; // 0부터 번까지 카운트하면 다시 0으로
cp_min = ~cp_min;
end
else cnt_sec = cnt_sec + 1;
end
end // 이렇게 카운트가 짝수일 경우, 위와 같이 코딩하여 1bit 줄일 수 있다.
// 비정규 clock이므로 동기화가 필요하다.
edge_detector_n edg(.clk(clk), .cp_in(cp_min), .rst(reset_p), .n_edge(clk_min)); /// 안 쓰는 출력은 빼버리면 된다.
endmodule
Stop Watch에 Instance
1. clock_min 모듈 Instance
2. FND의 남은 상위 두 자리에 counter_dec_60 Instance
module Stop_Watch_top(
input clk,
input reset_p,
input [1:0] btn, // 버튼 2개 쓸 것이므로
output [3:0] com,
output [7:0] seg_7
);
wire up_down_p;
reg start_stop;
// DFF를 위한 분주기
reg [16:0] clk_div;
always @(posedge clk) clk_div = clk_div + 1;
// 바운싱 제거용 DFF
D_flip_flop_n debnc_60(.d(btn[0]), .clk(clk_div[16]), .rst(reset_p), .q(start_stop)); //// 위의 clk divider의 16번쨰 bit를 써야 된다.
// 분주기 인스턴스
wire clk_usec, clk_msec, clk_sec;
clock_usec usec_clk(.clk(clk), .reset_p(reset_p), .clk_usec(clk_usec));
clock_msec msec_clk(.clk(clk), .clk_usec(clk_usec), .reset_p(reset_p), .clk_msec(clk_msec));
clock_sec sec_clk(.clk(clk), .clk_msec(clk_msec), .reset_p(reset_p), .clk_sec(clk_sec)); // 3가지 다 불러와야 sec 분주기 사용 가능
clock_min min_clk(.clk(clk), .clk_sec(clk_sec), .reset_p(reset_p), .clk_min(clk_min));
// 카운터 인스턴스
wire [3:0] sec1, sec10; // sec1 : 1의자리, sec10 : 10의 자리
counter_dec_60 cnt_60_sec(.clk(clk), .reset_p(reset_p), .clk_time(clk_sec), .dec1(sec1), .dec10(sec10));
wire [3:0] min1, min10;
counter_dec_60 cnt_60_min(.clk(clk), .reset_p(reset_p), .clk_time(clk_min), .dec1(min1), .dec10(min10));
FND_4digit_cntr fnd_cntr(.clk(clk), .rst(reset_p), .value({min10, min1, sec10, sec1}), .com(com), .seg_7(seg_7)); /// 컨트롤러가 분주기 가지고 있으니 그냥 clk준다.
endmodule
📌 Start/Stop 버튼 구현
Start/Stop 버튼 모듈 생성
버튼을 누를 때마다 Start/Stop되도록 설계
module start_stop(
input clk, reset_p,
input start_stop_input,
input btn,
output reg start_stop
);
always @(posedge clk, posedge reset_p) begin
if (reset_p) begin
start_stop <= 0; // 리셋 시에 초기화
end
else begin
// 버튼 누를 때마다 상태 토글
if (btn && !start_stop_input) begin
start_stop <= ~start_stop;
end
end
end
endmodule
enable 기능 추가
이전 clock_usec 모듈에 enable 기능 추가
// Cora board sys clock : 125MHz
// 1 clock 당, 8ns
// Micro sec clock
module clock_usec(
input clk, reset_p,
input enable,
output clk_usec
);
// 125개 카운트하면 1us
reg [6:0] cnt_8nsec;
wire cp_usec; // cp : clock pulse
always @(posedge clk, posedge reset_p) begin
if(reset_p) cnt_8nsec = 0; // reset이 들어오면 cnt = 0
else if (!enable) begin
if(cnt_8nsec >= 124) cnt_8nsec = 0; // 0부터 124번까지 카운트하면 다시 0으로
else cnt_8nsec = cnt_8nsec + 1;
end
end
assign cp_usec = cnt_8nsec < 63 ? 0 : 1; // 0~62 : 0, 63~124 : 1
// 비정규 clock이므로 동기화가 필요하다.
edge_detector_n edg(.clk(clk), .cp_in(cp_usec), .rst(reset_p), .n_edge(clk_usec)); /// 안 쓰는 출력은 빼버리면 된다.
endmodule
Stop Watch Top 모듈에 Instance
btn을 누르면, start/stop 신호가 토글되고 해당 신호를 clock의 enable에 연결하여
clock 활성화/비활성화 기능을 하도록 설계
module Stop_Watch_top(
input clk,
input reset_p,
input [1:0] btn, // 버튼 2개 쓸 것이므로
output [3:0] com,
output [7:0] seg_7
);
wire up_down_p, start_stop_input;
reg start_stop;
// DFF를 위한 분주기
reg [16:0] clk_div;
always @(posedge clk) clk_div = clk_div + 1;
// 바운싱 제거용 DFF
D_flip_flop_n debnc_60(.d(btn[0]), .clk(clk_div[16]), .rst(reset_p), .q(start_stop_input)); //// 위의 clk divider의 16번쨰 bit를 써야 된다.
// start_stop 버튼
start_stop srt_stp(.clk(clk), .reset_p(reset_p), .start_stop_input(start_stop_input), .btn(btn[0]), .start_stop(start_stop));
// 분주기 인스턴스
wire clk_usec, clk_msec, clk_sec;
clock_usec usec_clk(.clk(clk), .reset_p(reset_p), .enable(start_stop), .clk_usec(clk_usec));
clock_msec msec_clk(.clk(clk), .clk_usec(clk_usec), .reset_p(reset_p), .clk_msec(clk_msec));
clock_sec sec_clk(.clk(clk), .clk_msec(clk_msec), .reset_p(reset_p), .clk_sec(clk_sec)); // 3가지 다 불러와야 sec 분주기 사용 가능
clock_min min_clk(.clk(clk), .clk_sec(clk_sec), .reset_p(reset_p), .clk_min(clk_min));
// 카운터 인스턴스
wire [3:0] sec1, sec10; // sec1 : 1의자리, sec10 : 10의 자리
counter_dec_60 cnt_60_sec(.clk(clk), .reset_p(reset_p), .clk_time(clk_sec), .dec1(sec1), .dec10(sec10));
wire [3:0] min1, min10;
counter_dec_60 cnt_60_min(.clk(clk), .reset_p(reset_p), .clk_time(clk_min), .dec1(min1), .dec10(min10));
FND_4digit_cntr fnd_cntr(.clk(clk), .rst(reset_p), .value({min10, min1, sec10, sec1}), .com(com), .seg_7(seg_7)); /// 컨트롤러가 분주기 가지고 있으니 그냥 clk준다.
endmodule
📌 Lap 기능 구현
Lap 버튼 구현
T Flip-Flop를 활용하여 버튼의 토글 기능 구현(버튼 하나로 On/Off 가능)
DFF로 디바운싱, Edge Detector로 채터링 제거
// Lap 기능 구현
wire lap_input, lap_btn, lap;
D_flip_flop_n debnc_lap(.d(btn[1]), .clk(clk_div[16]), .rst(reset_p), .q(lap_input)); // 바운싱 제거용 DFF
edge_detector_n edg_lap(.clk(clk), .cp_in(lap_input), .rst(reset_p), .n_edge(lap_btn)); // Edga Detector
t_flip_flop_p tff_lap(.clk(clk), .rst(reset_p), .t(lap_btn), .q(lap)); // 토글을 위한 TFF
Lap data 저장할 레지스터 설계
// lap 데이터 저장을 위한 레지스터 생성
reg [15:0] lap_value;
always @(posedge clk, posedge reset_p) begin
if(reset_p) lap_value = 0;
else if(lap_btn) // lap_btn 나올 때 저장
lap_value = {min10, min1, sec10, sec1};
end
Lap Data Select
lap = 1 : lap_value 출력
lap = 0 : 현재 count 출력
// lap 버튼에 따른 FND 출력
wire [15:0] value;
assign value = lap ? lap_value : {min10, min1, sec10, sec1};
All Code(StopWatch)
module Stop_Watch_top(
input clk,
input reset_p,
input [1:0] btn, // 버튼 2개 쓸 것이므로
output [3:0] com,
output [7:0] seg_7
);
wire start_stop_input, start_stop, start_stop_btn;
// DFF를 위한 분주기
reg [16:0] clk_div;
always @(posedge clk) clk_div = clk_div + 1;
// Start_stop 기능 구현
D_flip_flop_n debnc_60(.d(btn[0]), .clk(clk_div[16]), .rst(reset_p), .q(start_stop_input)); // 바운싱 제거용 DFF
edge_detector_n edg_start_stop(.clk(clk), .cp_in(start_stop_input), .rst(reset_p), .n_edge(start_stop_btn)); // Edga Detector
start_stop_btn srt_stp(.clk(clk), .reset_p(reset_p), .start_stop_input(start_stop_btn), .btn(btn[0]), .start_stop(start_stop)); // start_stop 버튼 토글 기능
// Lap 기능 구현
wire lap_input, lap_btn, lap;
D_flip_flop_n debnc_lap(.d(btn[1]), .clk(clk_div[16]), .rst(reset_p), .q(lap_input)); // 바운싱 제거용 DFF
edge_detector_n edg_lap(.clk(clk), .cp_in(lap_input), .rst(reset_p), .n_edge(lap_btn)); // Edga Detector
t_flip_flop_p tff_lap(.clk(clk), .rst(reset_p), .t(lap_btn), .q(lap)); // 토글을 위한 TFF
// 분주기 인스턴스
wire clk_usec, clk_msec, clk_sec;
clock_usec usec_clk(.clk(clk), .reset_p(reset_p), .enable(start_stop), .clk_usec(clk_usec));
clock_msec msec_clk(.clk(clk), .clk_usec(clk_usec), .reset_p(reset_p), .clk_msec(clk_msec));
clock_sec sec_clk(.clk(clk), .clk_msec(clk_msec), .reset_p(reset_p), .clk_sec(clk_sec)); // 3가지 다 불러와야 sec 분주기 사용 가능
clock_min min_clk(.clk(clk), .clk_sec(clk_sec), .reset_p(reset_p), .clk_min(clk_min));
// 카운터 인스턴스
wire [3:0] sec1, sec10; // sec1 : 1의자리, sec10 : 10의 자리
counter_dec_60 cnt_60_sec(.clk(clk), .reset_p(reset_p), .clk_time(clk_sec), .dec1(sec1), .dec10(sec10)); // sec count
wire [3:0] min1, min10; // min1 : 1의자리, min10 : 10의 자리
counter_dec_60 cnt_60_min(.clk(clk), .reset_p(reset_p), .clk_time(clk_min), .dec1(min1), .dec10(min10)); // min count
// lap 데이터 저장을 위한 레지스터 생성
reg [15:0] lap_value;
always @(posedge clk, posedge reset_p) begin
if(reset_p) lap_value = 0;
else if(lap_btn) // lap_btn 나올 때 저장
lap_value = {min10, min1, sec10, sec1};
end
// lap 버튼에 따른 FND 출력
wire [15:0] value;
assign value = lap ? lap_value : {min10, min1, sec10, sec1};
FND_4digit_cntr fnd_cntr(.clk(clk), .rst(reset_p), .value(value), .com(com), .seg_7(seg_7)); /// 컨트롤러가 분주기 가지고 있으니 그냥 clk준다.
endmodule
[StopWatch All]
StopWatch_top
더보기
module Stop_Watch_top(
input clk,
input reset_p,
input [1:0] btn, // 버튼 2개 쓸 것이므로
output [3:0] com,
output [7:0] seg_7
);
wire start_stop_input, start_stop, start_stop_btn;
// DFF를 위한 분주기
reg [16:0] clk_div;
always @(posedge clk) clk_div = clk_div + 1;
// Start_stop 기능 구현
D_flip_flop_n debnc_60(.d(btn[0]), .clk(clk_div[16]), .rst(reset_p), .q(start_stop_input)); // 바운싱 제거용 DFF
edge_detector_n edg_start_stop(.clk(clk), .cp_in(start_stop_input), .rst(reset_p), .n_edge(start_stop_btn)); // Edga Detector
start_stop_btn srt_stp(.clk(clk), .reset_p(reset_p), .start_stop_input(start_stop_btn), .btn(btn[0]), .start_stop(start_stop)); // start_stop 버튼 토글 기능
// Lap 기능 구현
wire lap_input, lap_btn, lap;
D_flip_flop_n debnc_lap(.d(btn[1]), .clk(clk_div[16]), .rst(reset_p), .q(lap_input)); // 바운싱 제거용 DFF
edge_detector_n edg_lap(.clk(clk), .cp_in(lap_input), .rst(reset_p), .n_edge(lap_btn)); // Edga Detector
t_flip_flop_p tff_lap(.clk(clk), .rst(reset_p), .t(lap_btn), .q(lap)); // 토글을 위한 TFF
// 분주기 인스턴스
wire clk_usec, clk_msec, clk_sec;
clock_usec usec_clk(.clk(clk), .reset_p(reset_p), .enable(start_stop), .clk_usec(clk_usec));
clock_msec msec_clk(.clk(clk), .clk_usec(clk_usec), .reset_p(reset_p), .clk_msec(clk_msec));
clock_sec sec_clk(.clk(clk), .clk_msec(clk_msec), .reset_p(reset_p), .clk_sec(clk_sec)); // 3가지 다 불러와야 sec 분주기 사용 가능
clock_min min_clk(.clk(clk), .clk_sec(clk_sec), .reset_p(reset_p), .clk_min(clk_min));
// 카운터 인스턴스
wire [3:0] sec1, sec10; // sec1 : 1의자리, sec10 : 10의 자리
counter_dec_60 cnt_60_sec(.clk(clk), .reset_p(reset_p), .clk_time(clk_sec), .dec1(sec1), .dec10(sec10)); // sec count
wire [3:0] min1, min10; // min1 : 1의자리, min10 : 10의 자리
counter_dec_60 cnt_60_min(.clk(clk), .reset_p(reset_p), .clk_time(clk_min), .dec1(min1), .dec10(min10)); // min count
// Lap Value / value Select
reg [15:0] lap_value;
always @(posedge clk, posedge reset_p) begin
if(reset_p) lap_value = 0;
else if(lap_btn) // lap_btn 나올 때 저장
lap_value = {min10, min1, sec10, sec1};
end
// lap 버튼에 따른 FND 출력
wire [15:0] value;
assign value = lap ? lap_value : {min10, min1, sec10, sec1};
FND_4digit_cntr fnd_cntr(.clk(clk), .rst(reset_p), .value(value), .com(com), .seg_7(seg_7)); /// 컨트롤러가 분주기 가지고 있으니 그냥 clk준다.
endmodule
// 60bit_Counter
module counter_dec_60(
input clk, reset_p,
input clk_time,
output reg [3:0] dec1, dec10
);
always @(posedge clk, posedge reset_p) begin
if(reset_p) begin
dec1 = 0;
dec10 = 0;
end
else if(clk_time) begin
if(dec1 >= 9) begin
dec1 <= 0;
if(dec10 >= 5) dec10 = 0;
else dec10 <= dec10 + 1;
end
else dec1 <= dec1 + 1;
end
end
endmodule
// Start/Stop 버튼
module start_stop_btn(
input clk, reset_p,
input start_stop_input,
input btn,
output reg start_stop
);
always @(posedge clk, posedge reset_p) begin
if (reset_p) begin
start_stop <= 0; // 리셋 시에 초기화
end
else begin
// 버튼 누를 때마다 상태 토글
if (btn && !start_stop_input) begin
start_stop <= ~start_stop;
end
end
end
endmodule
Clock_Library
더보기
// Cora board sys clock : 125MHz
// 1 clock 당, 8ns
// Micro sec clock
module clock_usec(
input clk, reset_p,
input enable,
output clk_usec
);
// 125개 카운트하면 1us
reg [6:0] cnt_8nsec;
wire cp_usec; // cp : clock pulse
always @(posedge clk, posedge reset_p) begin
if(reset_p) cnt_8nsec = 0; // reset이 들어오면 cnt = 0
else if (!enable) begin
if(cnt_8nsec >= 124) cnt_8nsec = 0; // 0부터 124번까지 카운트하면 다시 0으로
else cnt_8nsec = cnt_8nsec + 1;
end
end
assign cp_usec = cnt_8nsec < 63 ? 0 : 1; // 0~62 : 0, 63~124 : 1
// 비정규 clock이므로 동기화가 필요하다.
edge_detector_n edg(.clk(clk), .cp_in(cp_usec), .rst(reset_p), .n_edge(clk_usec)); /// 안 쓰는 출력은 빼버리면 된다.
endmodule
// Mili sec clock
module clock_msec(
input clk, clk_usec, reset_p,
output clk_msec
);
// 1000개 카운트하면 1ms
// reg [9:0] cnt_usec;
// wire cp_msec; // cp : clock pulse
// always @(posedge clk, posedge reset_p) begin
// if(reset_p) cnt_usec = 0; // reset이 들어오면 cnt = 0
// else if (cnt_usec >= 999) cnt_usec = 0; // 0부터 125번까지 카운트하면 다시 0으로
// else cnt_usec = cnt_usec + 1;
// end
// assign cp_msec = cnt_usec < 499 ? 0 : 1; // 0~498 : 0, 499~1000 : 1
// 1000개 카운트하면 1ms
reg [8:0] cnt_usec;
reg cp_msec; // cp : clock pulse
always @(posedge clk, posedge reset_p) begin
if(reset_p) cnt_usec = 0; // reset이 들어오면 cnt = 0
else if(clk_usec) begin
if (cnt_usec >= 499) begin
cnt_usec = 0; // 0부터 499번까지 카운트하면 다시 0으로
cp_msec = ~cp_msec;
end
else cnt_usec = cnt_usec + 1;
end
end // 이렇게 카운트가 짝수일 경우, 위와 같이 코딩하여 1bit 줄일 수 있다.
// 비정규 clock이므로 동기화가 필요하다.
edge_detector_n edg(.clk(clk), .cp_in(cp_msec), .rst(reset_p), .n_edge(clk_msec)); /// 안 쓰는 출력은 빼버리면 된다.
endmodule
// sec clock
module clock_sec(
input clk, clk_msec, reset_p,
output clk_sec
);
// 1000개 카운트하면 1s
reg [8:0] cnt_msec;
reg cp_sec; // cp : clock pulse
always @(posedge clk, posedge reset_p) begin
if(reset_p) cnt_msec = 0; // reset이 들어오면 cnt = 0
else if(clk_msec) begin
if (cnt_msec >= 499) begin
cnt_msec = 0; // 0부터 499번까지 카운트하면 다시 0으로
cp_sec = ~cp_sec; // clock pulse 반전
end
else cnt_msec = cnt_msec + 1;
end
end // 이렇게 카운트가 짝수일 경우, 위와 같이 코딩하여 1bit 줄일 수 있다.
// 비정규 clock이므로 동기화가 필요하다.
edge_detector_n edg(.clk(clk), .cp_in(cp_sec), .rst(reset_p), .n_edge(clk_sec)); /// 안 쓰는 출력은 빼버리면 된다.
endmodule
// min clock
module clock_min(
input clk, clk_sec, reset_p,
output clk_min
);
// 60개 카운트하면 1s
reg [5:0] cnt_sec;
reg cp_min; // cp : clock pulse
always @(posedge clk, posedge reset_p) begin
if(reset_p) cnt_sec = 0; // reset이 들어오면 cnt = 0
else if(clk_sec) begin
if (cnt_sec >= 29) begin
cnt_sec = 0; // 0부터 번까지 카운트하면 다시 0으로
cp_min = ~cp_min;
end
else cnt_sec = cnt_sec + 1;
end
end // 이렇게 카운트가 짝수일 경우, 위와 같이 코딩하여 1bit 줄일 수 있다.
// 비정규 clock이므로 동기화가 필요하다.
edge_detector_n edg(.clk(clk), .cp_in(cp_min), .rst(reset_p), .n_edge(clk_min)); /// 안 쓰는 출력은 빼버리면 된다.
endmodule
FND_Controller
더보기
module FND_4digit_cntr( //// ring counter top module 생성 ---- 16bit의 값을 받아서 1ms 간격으로 한 자리씩 켜준다.
input clk, rst, lap,
input [15:0] value, //// 4자리니까 16bit
output [3:0] com,
output [7:0] seg_7
);
reg [16:0] clk_1ms;//// 8ns * 2^17 = 1,048,576ns = 1048㎲ = 1.048ms
always @(posedge clk) clk_1ms = clk_1ms + 1 ;
ring_count_fnd ring1(.clk(clk_1ms[16]), .com(com)); //// 1ms posedge마다 좌시프트
//// 1ms 마다 CT 순대로 LED가 점멸한다.
wire [7:0] seg_7_font;
reg [3:0] hex_value;
decoder_7seg ring_seg_7(.hex_value(hex_value), .seg_7(seg_7_font));
assign seg_7 = ~seg_7_font;
always @(negedge clk) begin //// 카운팅은 posedge에 했으니, 겹치지 않게 negedge
case(com)
4'b1110 : hex_value = value[15:12]; //// CT1에 해당하는 hex_value는 value[15:12]
4'b1101 : hex_value = value[11:8];
4'b1011 : hex_value = value[7:4];
4'b0111 : hex_value = value[3:0];
endcase //// edge triggering은 default에서 현재 값을 유지해도 FF가 만들어지니 상관없다.
end
endmodule
728x90
반응형