Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- hc-sr04
- D Flip Flop
- Edge Detector
- vivado
- Pspice
- Recursion
- test bench
- gpio
- verilog
- FND
- prescaling
- KEYPAD
- Linked List
- i2c 통신
- uart 통신
- ring counter
- structural modeling
- BASYS3
- dataflow modeling
- LED
- DHT11
- atmega 128a
- ATMEGA128A
- behavioral modeling
- half adder
- stop watch
- java
- pwm
- Algorithm
- soc 설계
Archives
- Today
- Total
거북이처럼 천천히
4X4 Matrix KeyPad - 2 본문
1. 4X4 Matrix KeyPad (FSM 형식)
- 이번에는 FSM (= Finite State Machine) 형식으로 KeyPad를 구현해보도록 하겠다.
- 아래와 같이 5가지 상태로 정의하였다.
- S_SCAN0 ~ S_SCAN3 : 0번째 행부터 3번째 행까지를 10msec 주기로 순회하면서 버튼이 눌렀는지
여부 확인하는 상태
- S_KEY_PROCESS : 버튼이 눌렀을 경우, 어떤 버튼이 눌렀는지를 확인하고, 이를 출력으로 내보내는 상태 - 소스 코드에 대한 자세한 설명은 아래 게시글을 참고하길 바란다.
https://jbhdeve.tistory.com/275
< Source, Clock Divider 1000 >
// Clock divider 1000
module clk_div_1000 (
input clk, reset_p,
input clk_source,
output clk_div_1000,
output clk_div_1000_nedge, clk_div_1000_pedge );
wire clk_source_nedge;
edge_detector edge_detector_0 (.clk(clk), .reset_p(reset_p), .cp(clk_source), .n_edge(clk_source_nedge));
reg [9:0] counter;
always @(posedge clk or posedge reset_p) begin
if(reset_p) counter = 0;
else if(clk_source_nedge) begin
if(counter >= 999) counter = 0;
else counter = counter + 1;
end
end
assign clk_div_1000 = (counter < 500)? 0 : 1;
edge_detector edge_detector_1 (.clk(clk), .reset_p(reset_p), .cp(clk_div_1000), .n_edge(clk_div_1000_nedge), .p_edge(clk_div_1000_pedge));
endmodule
< Source, Clock Divider 100 >
// Clock divider 100
module clk_div_100 (
input clk, reset_p,
output clk_div_100,
output clk_div_100_nedge, clk_div_100_pedge );
reg [6:0] counter;
always @(posedge clk or posedge reset_p) begin
if(reset_p) counter = 0;
else begin
if(counter >= 99) counter = 0;
else counter = counter + 1;
end
end
assign clk_div_100 = (counter < 50)? 0 : 1;
edge_detector edge_detector_0 (.clk(clk), .reset_p(reset_p), .cp(clk_div_100), .n_edge(clk_div_100_nedge), .p_edge(clk_div_100_pedge));
endmodule
< Source, Edge detector >
// Edge detector
module edge_detector (
input clk, reset_p,
input cp,
output n_edge, p_edge );
reg flip_flop_current, flip_flop_old;
always @(posedge clk or posedge reset_p) begin
if(reset_p) begin flip_flop_current <= 0; flip_flop_old <= 0; end
else begin
flip_flop_current <= cp;
flip_flop_old <= flip_flop_current;
end
end
assign p_edge = ({flip_flop_current, flip_flop_old} == 2'b10) ? 1 : 0;
assign n_edge = ({flip_flop_current, flip_flop_old} == 2'b01) ? 1 : 0;
endmodule
< Source, Decoder of 7-Segment >
// Decoder of 7-segment.
module decoder_seg7 (
input [3:0] hex_value,
output reg [7:0] seg_7 );
always @(hex_value) begin
case(hex_value)
0 : seg_7 = 8'b0000_0011; //common anode, 0이 켜지는거임
1 : seg_7 = 8'b1001_1111; // 1
2 : seg_7 = 8'b0010_0101; // 2
3 : seg_7 = 8'b0000_1101; // 3
4 : seg_7 = 8'b1001_1001; // 4
5 : seg_7 = 8'b0100_1001; // 5
6 : seg_7 = 8'b0100_0001; // 6
7 : seg_7 = 8'b0001_1111; // 7
8 : seg_7 = 8'b0000_0001; // 8
9 : seg_7 = 8'b0000_1001; // 9
10 : seg_7 = 8'b0001_0001; // A
11 : seg_7 = 8'b1100_0001; // b
12 : seg_7 = 8'b0110_0011; // C
13 : seg_7 = 8'b1000_0101; // d
14 : seg_7 = 8'b0110_0001; // E
15 : seg_7 = 8'b0111_0001; // F
endcase
end
endmodule
< Source, Ring Counter of com >
// Ring Counter
module ring_counter (
input clk, reset_p,
output reg [3:0] com );
// Get 1msec One Cycle Pulse
wire clk_1usec, clk_1msec;
clk_div_100 clk_div_1usec (.clk(clk), .reset_p(reset_p), .clk_div_100(clk_1usec));
clk_div_1000 clk_div_1msec (.clk(clk), .reset_p(reset_p), .clk_source(clk_1usec), .clk_div_1000_nedge(clk_1msec));
always @(posedge clk or posedge reset_p) begin
if(reset_p) com = 4'b1110;
else if(clk_1msec) com = {com[2:0], com[3]};
end
endmodule
< Source, FND Control >
// Control FND
module fnd_cntr (
input clk, reset_p,
input [15:0] hex_value,
output [3:0] com,
output [7:0] seg_7 );
// Ring Counter of com
ring_counter ring_counter_0 (.clk(clk), .reset_p(reset_p), .com(com));
// Select value & Print value on FND,
reg [3:0] value;
always @(posedge clk or posedge reset_p) begin
if(reset_p) value = 4'b0;
else begin
case(com)
4'b1110 : value = hex_value [3:0];
4'b1101 : value = hex_value [7:4];
4'b1011 : value = hex_value [11:8];
4'b0111 : value = hex_value [15:12];
default : value = value;
endcase
end
end
decoder_seg7 decoder_7_segment (.hex_value(value), .seg_7(seg_7));
endmodule
< Source, KeyPad Control >
// Control KeyPad
module Keypad_cntr(
input clk, reset_p,
input [3:0] col,
output reg [3:0] row,
output reg [3:0] key_value,
output [4:0] state_led );
// State LED
assign state_led = state;
// Declare State.
parameter S_SCAN0 = 5'b00001;
parameter S_SCAN1 = 5'b00010;
parameter S_SCAN2 = 5'b00100;
parameter S_SCAN3 = 5'b01000;
parameter S_KEY_PROCESS = 5'b10000;
// Get 8msec One Cycle Pulse
wire clk_10msec;
reg [19:0] counter;
always @(posedge clk or posedge reset_p) begin
if(reset_p) counter = 0;
else counter = counter + 1;
end
edge_detector edge_detector_0 (.clk(clk), .reset_p(reset_p), .cp(counter[19]), .n_edge(clk_10msec));
// Declare Variable of state.
reg [4:0] state, next_state;
// 언제 다음 상태로 넘어가는가?
always @(posedge clk or posedge reset_p) begin
if(reset_p) begin state = S_SCAN0; end
else if(clk_10msec) state = next_state;
end
// 다음 조건으로 넘어가기 위한 조건 설정
always @(*) begin
case(state)
S_SCAN0 : begin
if(col == 0) next_state = S_SCAN1;
else next_state = S_KEY_PROCESS;
end
S_SCAN1 : begin
if(col == 0) next_state = S_SCAN2;
else next_state = S_KEY_PROCESS;
end
S_SCAN2 : begin
if(col == 0) next_state = S_SCAN3;
else next_state = S_KEY_PROCESS;
end
S_SCAN3 : begin
if(col == 0) next_state = S_SCAN0;
else next_state = S_KEY_PROCESS;
end
S_KEY_PROCESS : begin
if(col == 0) next_state = S_SCAN0;
else next_state = S_KEY_PROCESS;
end
default : next_state = S_SCAN0;
endcase
end
// 각 state 마다 동작 설정.
always @(negedge clk or posedge reset_p) begin
if(reset_p) begin
key_value = 0;
row = 0;
end
else begin
case(state)
S_SCAN0 : begin row = S_SCAN0; end
S_SCAN1 : begin row = S_SCAN1; end
S_SCAN2 : begin row = S_SCAN2; end
S_SCAN3 : begin row = S_SCAN3; end
S_KEY_PROCESS : begin
case({row, col})
8'b0001_0001 : key_value = 16'h0;
8'b0001_0010 : key_value = 16'h1;
8'b0001_0100 : key_value = 16'h2;
8'b0001_1000 : key_value = 16'h3;
8'b0010_0001 : key_value = 16'h4;
8'b0010_0010 : key_value = 16'h5;
8'b0010_0100 : key_value = 16'h6;
8'b0010_1000 : key_value = 16'h7;
8'b0100_0001 : key_value = 16'h8;
8'b0100_0010 : key_value = 16'h9;
8'b0100_0100 : key_value = 16'ha;
8'b0100_1000 : key_value = 16'hb;
8'b1000_0001 : key_value = 16'hc;
8'b1000_0010 : key_value = 16'hd;
8'b1000_0100 : key_value = 16'he;
8'b1000_1000 : key_value = 16'hf;
default : key_value = key_value;
endcase
end
endcase
end
end
endmodule
< Source, Top module of 4X4 Matrix KeyPad >
// Top Module of key pad
module top_module_of_keypad (
input clk, reset_p,
input [3:0] col,
output [3:0] com,
output [7:0] seg_7,
output [3:0] row,
output [4:0] state_led);
wire [3:0] key_value;
Keypad_cntr control_keypad (.clk(clk), .reset_p(reset_p), .col(col), .row(row), .key_value(key_value), .state_led(state_led));
fnd_cntr control_fnd (.clk(clk), .reset_p(reset_p), .hex_value({12'b0, key_value}), .com(com), .seg_7(seg_7));
endmodule
2. 구동 영상
3. 전체 소스 코드
// Top Module of key pad
module top_module_of_keypad (
input clk, reset_p,
input [3:0] col,
output [3:0] com,
output [7:0] seg_7,
output [3:0] row,
output [4:0] state_led);
wire [3:0] key_value;
Keypad_cntr control_keypad (.clk(clk), .reset_p(reset_p), .col(col), .row(row), .key_value(key_value), .state_led(state_led));
fnd_cntr control_fnd (.clk(clk), .reset_p(reset_p), .hex_value({12'b0, key_value}), .com(com), .seg_7(seg_7));
endmodule
// Control KeyPad
module Keypad_cntr(
input clk, reset_p,
input [3:0] col,
output reg [3:0] row,
output reg [3:0] key_value,
output [4:0] state_led );
// State LED
assign state_led = state;
// Declare State.
parameter S_SCAN0 = 5'b00001;
parameter S_SCAN1 = 5'b00010;
parameter S_SCAN2 = 5'b00100;
parameter S_SCAN3 = 5'b01000;
parameter S_KEY_PROCESS = 5'b10000;
// Get 8msec One Cycle Pulse
wire clk_10msec;
reg [19:0] counter;
always @(posedge clk or posedge reset_p) begin
if(reset_p) counter = 0;
else counter = counter + 1;
end
edge_detector edge_detector_0 (.clk(clk), .reset_p(reset_p), .cp(counter[19]), .n_edge(clk_10msec));
// Declare Variable of state.
reg [4:0] state, next_state;
// 언제 다음 상태로 넘어가는가?
always @(posedge clk or posedge reset_p) begin
if(reset_p) begin state = S_SCAN0; end
else if(clk_10msec) state = next_state;
end
// 다음 조건으로 넘어가기 위한 조건 설정
always @(*) begin
case(state)
S_SCAN0 : begin
if(col == 0) next_state = S_SCAN1;
else next_state = S_KEY_PROCESS;
end
S_SCAN1 : begin
if(col == 0) next_state = S_SCAN2;
else next_state = S_KEY_PROCESS;
end
S_SCAN2 : begin
if(col == 0) next_state = S_SCAN3;
else next_state = S_KEY_PROCESS;
end
S_SCAN3 : begin
if(col == 0) next_state = S_SCAN0;
else next_state = S_KEY_PROCESS;
end
S_KEY_PROCESS : begin
if(col == 0) next_state = S_SCAN0;
else next_state = S_KEY_PROCESS;
end
default : next_state = S_SCAN0;
endcase
end
// 각 state 마다 동작 설정.
always @(negedge clk or posedge reset_p) begin
if(reset_p) begin
key_value = 0;
row = 0;
end
else begin
case(state)
S_SCAN0 : begin row = S_SCAN0; end
S_SCAN1 : begin row = S_SCAN1; end
S_SCAN2 : begin row = S_SCAN2; end
S_SCAN3 : begin row = S_SCAN3; end
S_KEY_PROCESS : begin
case({row, col})
8'b0001_0001 : key_value = 16'h0;
8'b0001_0010 : key_value = 16'h1;
8'b0001_0100 : key_value = 16'h2;
8'b0001_1000 : key_value = 16'h3;
8'b0010_0001 : key_value = 16'h4;
8'b0010_0010 : key_value = 16'h5;
8'b0010_0100 : key_value = 16'h6;
8'b0010_1000 : key_value = 16'h7;
8'b0100_0001 : key_value = 16'h8;
8'b0100_0010 : key_value = 16'h9;
8'b0100_0100 : key_value = 16'ha;
8'b0100_1000 : key_value = 16'hb;
8'b1000_0001 : key_value = 16'hc;
8'b1000_0010 : key_value = 16'hd;
8'b1000_0100 : key_value = 16'he;
8'b1000_1000 : key_value = 16'hf;
default : key_value = key_value;
endcase
end
endcase
end
end
endmodule
// Control FND
module fnd_cntr (
input clk, reset_p,
input [15:0] hex_value,
output [3:0] com,
output [7:0] seg_7 );
// Ring Counter of com
ring_counter ring_counter_0 (.clk(clk), .reset_p(reset_p), .com(com));
// Select value & Print value on FND,
reg [3:0] value;
always @(posedge clk or posedge reset_p) begin
if(reset_p) value = 4'b0;
else begin
case(com)
4'b1110 : value = hex_value [3:0];
4'b1101 : value = hex_value [7:4];
4'b1011 : value = hex_value [11:8];
4'b0111 : value = hex_value [15:12];
default : value = value;
endcase
end
end
decoder_seg7 decoder_7_segment (.hex_value(value), .seg_7(seg_7));
endmodule
// Ring Counter
module ring_counter (
input clk, reset_p,
output reg [3:0] com );
// Get 1msec One Cycle Pulse
wire clk_1usec, clk_1msec;
clk_div_100 clk_div_1usec (.clk(clk), .reset_p(reset_p), .clk_div_100(clk_1usec));
clk_div_1000 clk_div_1msec (.clk(clk), .reset_p(reset_p), .clk_source(clk_1usec), .clk_div_1000_nedge(clk_1msec));
always @(posedge clk or posedge reset_p) begin
if(reset_p) com = 4'b1110;
else if(clk_1msec) com = {com[2:0], com[3]};
end
endmodule
// Decoder of 7-segment.
module decoder_seg7 (
input [3:0] hex_value,
output reg [7:0] seg_7 );
always @(hex_value) begin
case(hex_value)
0 : seg_7 = 8'b0000_0011; //common anode, 0이 켜지는거임
1 : seg_7 = 8'b1001_1111; // 1
2 : seg_7 = 8'b0010_0101; // 2
3 : seg_7 = 8'b0000_1101; // 3
4 : seg_7 = 8'b1001_1001; // 4
5 : seg_7 = 8'b0100_1001; // 5
6 : seg_7 = 8'b0100_0001; // 6
7 : seg_7 = 8'b0001_1111; // 7
8 : seg_7 = 8'b0000_0001; // 8
9 : seg_7 = 8'b0000_1001; // 9
10 : seg_7 = 8'b0001_0001; // A
11 : seg_7 = 8'b1100_0001; // b
12 : seg_7 = 8'b0110_0011; // C
13 : seg_7 = 8'b1000_0101; // d
14 : seg_7 = 8'b0110_0001; // E
15 : seg_7 = 8'b0111_0001; // F
endcase
end
endmodule
// Edge detector
module edge_detector (
input clk, reset_p,
input cp,
output n_edge, p_edge );
reg flip_flop_current, flip_flop_old;
always @(posedge clk or posedge reset_p) begin
if(reset_p) begin flip_flop_current <= 0; flip_flop_old <= 0; end
else begin
flip_flop_current <= cp;
flip_flop_old <= flip_flop_current;
end
end
assign p_edge = ({flip_flop_current, flip_flop_old} == 2'b10) ? 1 : 0;
assign n_edge = ({flip_flop_current, flip_flop_old} == 2'b01) ? 1 : 0;
endmodule
// Clock divider 100
module clk_div_100 (
input clk, reset_p,
output clk_div_100,
output clk_div_100_nedge, clk_div_100_pedge );
reg [6:0] counter;
always @(posedge clk or posedge reset_p) begin
if(reset_p) counter = 0;
else begin
if(counter >= 99) counter = 0;
else counter = counter + 1;
end
end
assign clk_div_100 = (counter < 50)? 0 : 1;
edge_detector edge_detector_0 (.clk(clk), .reset_p(reset_p), .cp(clk_div_100), .n_edge(clk_div_100_nedge), .p_edge(clk_div_100_pedge));
endmodule
// Clock divider 1000
module clk_div_1000 (
input clk, reset_p,
input clk_source,
output clk_div_1000,
output clk_div_1000_nedge, clk_div_1000_pedge );
wire clk_source_nedge;
edge_detector edge_detector_0 (.clk(clk), .reset_p(reset_p), .cp(clk_source), .n_edge(clk_source_nedge));
reg [9:0] counter;
always @(posedge clk or posedge reset_p) begin
if(reset_p) counter = 0;
else if(clk_source_nedge) begin
if(counter >= 999) counter = 0;
else counter = counter + 1;
end
end
assign clk_div_1000 = (counter < 500)? 0 : 1;
edge_detector edge_detector_1 (.clk(clk), .reset_p(reset_p), .cp(clk_div_1000), .n_edge(clk_div_1000_nedge), .p_edge(clk_div_1000_pedge));
endmodule
'RTL Design > Verilog 연습' 카테고리의 다른 글
DHT11 - 1 (0) | 2024.08.11 |
---|---|
10kHz인 PWM 설계 (Duty ratio stage 100단계) - (1) (0) | 2024.08.11 |
4X4 Matrix KeyPad - 1 (0) | 2024.08.09 |
Stop Watch - 1 (0) | 2024.08.07 |
Advanced Clock (0) | 2024.08.06 |