프로그래밍/텀프로젝트

[전기전자기초실험/Verilog]디지털 도어락 설계

RAVIN 2022. 2. 7. 12:30

2학기 전기전자기초실험 텀프로젝트

FPGA와 HDL을 사용하여 디지털 도어락 만들기

 

1. 사용 FPGA

Digcom V3.2

 

2. 요구사항

순서 테스트 항목 확인 사항
1 초기 상태 1-1. 7 세그먼트 모두 OFF (대기 모드)
1-2. 8LED 모두 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. 입력한 암호와 내부 저장된 암호 불일치의 경우,
모든 LEDON되어 문 잠김 상태
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 signalsynchronus 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 작동하는 MCLK1Hz로 분주.

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. 전체 코드

디지털도어락.zip
0.01MB