2학기 전기전자기초실험 텀프로젝트
FPGA와 HDL을 사용하여 디지털 도어락 만들기
1. 사용 FPGA
2. 요구사항
순서 | 테스트 항목 | 확인 사항 |
1 | 초기 상태 | 1-1. 7 세그먼트 모두 OFF (대기 모드) |
1-2. 8개 LED 모두 ON (문 잠김) | ||
1-3. 내무에 저장되는 초기 암호 “123456”으로 초기화 | ||
2 | 암호 입력 모드 SW 'A' |
가운데 세그먼트(하이픈, ‘-’)만 ON “암호 입력 모드” 표시 |
3 | 암호 입력 SW '1'~'6' |
초기 암호 “123456”를 입력함에 따라 좌측의 7 세그먼트부터 입력된 숫자 표시 |
4 | 암호 확인 SW 'A' |
4-1. 8개의 LED가 순차적으로 모두 OFF 문 열림 상태로 변경 |
4-2. 7 세그먼트가 모두 OFF “대기 모드”로 전환 | ||
5 | 암호 설정 모드 SW 'B' |
아래 세그먼트(언더라인, ‘_’)만 ON “암호 설정 모드” 표시 |
6 | 암호 입력 SW '0'~'9' |
10개의 숫자 중에서 6개를 조합하여 입력함에 따라 좌측의 7 세그먼트부터 입력된 숫자 표시 |
7 | 암호 설정 SW 'B' |
7-1. 모든 7 세그먼트에 숫자 ‘8’을 2번 점멸 후 OFF |
7-2. 내부에 저장된 암호를 임의의 6개 숫자로 변경 | ||
8 | 문 잠금 SW 'A' |
8개의 모든 LED가 순차적으로 ON 문 잠김 상태로 변경 |
9 | 암호 설정 모드 SW 'B' |
문이 잠긴 상태에서는 “암호 설정 모드”로 변경되지 않음 |
10 | 암호 입력 모드 SW 'A' |
‘순서 2’의 상태와 동일하게 “암호 입력 모드”로 변경 |
11 | 암호 입력 SW '1'~'6' |
‘순서 3’과 같이 초기 암호를 입력할 때, 좌측의 7 세그먼트부터 입력된 숫자 표시 |
12 | 암호 확인 SW 'A' |
12-1. 모든 7 세그먼트 OFF “대기 모드”로 변경 |
12-2. 입력한 암호와 내부 저장된 암호 불일치의 경우, 모든 LED는 ON되어 문 잠김 상태 |
||
13 | 암호 입력 모드 SW 'A' |
“순서 2”의 상태와 동일하게 “암호 입력 모드”로 변경 |
14 | 암호 입력 SW '1'~'6' |
변경 후의 암호를 입력할 때, 좌측의 7 세그먼트부터 입력된 숫자 표시 |
15 | 암호 확인 SW 'A' |
15-1. 8개의 LED가 순차적으로 모두 OFF 문 열림 상태로 변경 |
15-2. 모든 7 세그먼트 LED OFF “대기 모드”로 변경 |
3. 블록선도및 블록별 역할/입출력
switch interface
목적: 비동기 입력을 받아 동기화된 숫자 데이터를 control unit에 전달.
I/O table | ||
I/O | identifier | means |
Input | MCLK | 마스터클럭 |
KEY_INP [11:0] | 푸시버튼으로부터 받은 비동기 입력 | |
Output | NUM_OUT [3:0] | 동기화된 16진수 숫자 1개 |
동작과정:
사용자로부터 받은 asynchronus signal을 synchronus signal 로 변환
사용자로부터 받은 입력, 즉 한 자리의 16진수 데이터를 출력신호로 보냄. 이때 계속 출력하는 것이 아니라 엣지 디텍터를 통해 하나의 사각 펄스로 출력시킴. (이 부분은 테스트벤치 파형 참고)
(중요) 입력이 없는 상태를 구분하기 위해, 입력이 없는 상태는 NUM_OUT [3:0] = 4‘h0 이며 “0” 입력은 NUM_OUT [3:0] = 4’hC 로 구현함.
state machine:
목적: state 변환 등 전체적인 제어 수행.
I/O table | ||
I/O | identifier | means |
Input | MCLK | 마스터클럭 |
rINTER_INP [3:0] | Interface로부터 받은 16진수 정수 | |
PW_SIG | password storage로부터 받은 1비트 신호 | |
Output | reg NUMBER_OUT [23:0] | 16진수 숫자 배열(사이즈 6) |
reg STATE_SIG [1:0] | 현재 상태를 출력 | |
동작과정:
1. 6자리의 16진수 배열 NUMBER_OUT [23:0] 출력을 위해 4비트 버퍼 6개와 포인터 변수 사용함. (C언어의 포인터와 비슷한 개념이며 배열의 주소를 가리키제 함.)
2. 6자리 숫자 입력이 끝나면 포인터를 초기화함과 동시에 입력버퍼 또한 0으로 초기화함. 단 이때 출력
NUMBER_OUT [23:0] 은 초기화하지 않음.
3. 또한 Switch Interface로부터 받은 입력과 PW storage로부터 받은 신호들을 사용하여 전체 도어락의 상태변경 실행.
PW storage:
목적: 패스워드를 저장하거나 control unit으로부터 전달받은 패스워드를 비교 혹은 재설정.
I/O table | ||
I/O | identifier | means |
Input | MCLK | 마스터클럭 |
STATUS [1:0] | state머신으로부터 받은 상태변수 | |
NUMBER_ARR [23:0] | state머신으로부터 받은 16진수 정수배열 | |
Output | COMPSIG | 도어락의 열림/잠금상태 판단 |
동작과정:
6자리의 16진수 배열 NUMBER_OUT [23:0] 입력과 State 신호를 받아 조건문을 활용하여 패스워드를 비교하거나 재설정한다. 또한 도어락의 개폐 여부를 COMPSIG 신호로 외부로 전달한다.
LED Display(조원 제작):
현재 state에 적절한 디스플레이 출력.
I/O table | ||
I/O | identifier | means |
Input | MCLK | 마스터클럭 |
LrState[1:0] | state머신으로부터 받은 상태변수 | |
Output | LED[8:1] | 도어락의 열림/닫힘을 보여주는 LED 값 |
동작과정:
1. 0.1초마다 led가 변하기 때문에 1MHz 작동하는 MCLK를 1Hz로 분주.
2. LrState값의 변화에 따라 LED가 켜지고 증가하는 걸 정함.
3. if절을 이용하여 앞의 값이 변화하면 뒤의 값이 순차적으로 변하도록 함.
7seg Display(조원 제작):
목적: 현재 state에 적절한 디스플레이 출력.
I/O table | ||
I/O | identifier | means |
Input | MCLK | 마스터클럭 |
SgState[1:0] | state머신으로부터 받는 상태변수 | |
sgINTER_INP[3:0] | interface에서 받는 input 값 | |
Output | segment1~6[6:0] | 각각 segment 할당 값 |
동작과정:
입력된 sgINTER_INP라는 비동기입력을 동기입력으로 바꿔 동기입력 INTER_INP를 받음.
sgcount라는 변수를 포인터로 이용, 입력이 들어올 때마다 1씩 증가시키며 segment를 출력.
각각 1~9까지의 입력받은 수의 세그먼트값은 변수 sgk에 저장하여 segment로 넣음으로써 쉽게 변화를 줄 수 있도록 함.
S3(비밀번호 변경)에서 S1으로 갈 때, S0count라는 변수를 통해 분주, 0.5초마다 888888이 출력되도록 분주함.
3. 최상위 블록 HDL코드 및 testbench 코드, 시뮬레이션 결과
<설계코드>
module ModuleTest ( input MCLK, //master clock input [11:0]userkey, //pushbutton from user output [8:1] ledout, output [6:0] Segment1, output [6:0] Segment2, output [6:0] Segment3, output [6:0] Segment4, output [6:0] Segment5, output [6:0] Segment6 ); wire [3:0]NUM_OUT; wire [1:0]STATUS; wire [23:0]NUMBER_OUT; wire PW_SIG; SwitchInterface SWINT(.MCLK(MCLK), .KEY_INP(userkey), .NUM_OUT(NUM_OUT)); StateMachine STME(.MCLK(MCLK), .rINTER_INP(NUM_OUT), .PW_SIG(PW_SIG), .NUMBER_OUT(NUMBER_OUT), .STATE_SIG(STATUS)); PWstorage PWS(.MCLK(MCLK), .STATUS(STATUS), .NUMBER_ARR(NUMBER_OUT), .COMPSIG(PW_SIG)); LEDdisplay LEDD(.MCLK(MCLK), .LrState(STATUS), .LED(ledout)); Segment SEG(.MCLK(MCLK), .SgState(STATUS), .sgINTER_INP(NUM_OUT), .segment1(Segment1), .segment2(Segment2), .segment3(Segment3) , .segment4(Segment4), .segment5(Segment5), .segment6(Segment6)); endmodule |
<testbench>
`timescale 1ns/100ps module ModuleTest_tb; reg MCLK = 1'b0; reg [11:0]userkey = 12'b0; wire [8:1] ledout; wire [6:0] Segment1; wire [6:0] Segment2; wire [6:0] Segment3; wire [6:0] Segment4; wire [6:0] Segment5; wire [6:0] Segment6; ModuleTest FMTB ( .MCLK(MCLK), .userkey(userkey), .ledout(ledout), .Segment1(Segment1), .Segment2(Segment2), .Segment3(Segment3), .Segment4(Segment4), .Segment5(Segment5), .Segment6(Segment6) ); always #5 MCLK <= ~MCLK; initial begin #50 userkey[10] = 1'b1; //push A button #50 userkey[10] = 1'b0; #50 userkey[1] = 1'b1; //push password 123456 #50 userkey[1] = 1'b0; #50 userkey[2] = 1'b1; #50 userkey[2] = 1'b0; #50 userkey[3] = 1'b1; #50 userkey[3] = 1'b0; #50 userkey[4] = 1'b1; #50 userkey[4] = 1'b0; #50 userkey[5] = 1'b1; #50 userkey[5] = 1'b0; #50 userkey[6] = 1'b1; #50 userkey[6] = 1'b0; #50 userkey[10] = 1'b1; //push A button #50 userkey[10] = 1'b0; #50000 userkey[11] = 1'b1; //push B button #50 userkey[11] = 1'b0; #50 userkey[6] = 1'b1; //resetting password #50 userkey[6] = 1'b0; #50 userkey[5] = 1'b1; #50 userkey[5] = 1'b0; #50 userkey[4] = 1'b1; #50 userkey[4] = 1'b0; #50 userkey[3] = 1'b1; #50 userkey[3] = 1'b0; #50 userkey[2] = 1'b1; #50 userkey[2] = 1'b0; #50 userkey[1] = 1'b1; #50 userkey[1] = 1'b0; #50 userkey[11] = 1'b1; //push B button #50 userkey[11] = 1'b0; #50 userkey[10] = 1'b1; //push A button #50 userkey[10] = 1'b0; #50000 userkey[1] = 1'b1; //push wrong password 123456 #50 userkey[1] = 1'b0; #50 userkey[2] = 1'b1; #50 userkey[2] = 1'b0; #50 userkey[3] = 1'b1; #50 userkey[3] = 1'b0; #50 userkey[4] = 1'b1; #50 userkey[4] = 1'b0; #50 userkey[5] = 1'b1; #50 userkey[5] = 1'b0; #50 userkey[6] = 1'b1; #50 userkey[6] = 1'b0; #50 userkey[10] = 1'b1; //push A button #50 userkey[10] = 1'b0; #50 userkey[6] = 1'b1; //resetting password #50 userkey[6] = 1'b0; #50 userkey[5] = 1'b1; #50 userkey[5] = 1'b0; #50 userkey[4] = 1'b1; #50 userkey[4] = 1'b0; #50 userkey[3] = 1'b1; #50 userkey[3] = 1'b0; #50 userkey[2] = 1'b1; #50 userkey[2] = 1'b0; #50 userkey[1] = 1'b1; #50 userkey[1] = 1'b0; #50 userkey[10] = 1'b1; //push A button #50 userkey[10] = 1'b0; end endmodule |
<시뮬레이션 파형>
4. 실제 시연 영상
2021 전기전자기초실험(2) 디지털도어락 최종시연영상 - YouTube
5. 전체 코드