// 구글 검색 // 네이버 검색

지난 글에서 설명한 이론을 바탕으로 이번에는 단일 스위치에서 시작해 스위치 매트릭스까지 한단계씩 확장해가며 키보드에 사용할 회로를 만들어 보겠습니다.

 

접지 라인 통합

아두이노에 스위치를 하나만 연결한다면 아래 그림의 왼쪽처럼 회로를 구성할 수 있습니다. 스위치 2개를 독립적으로 연결한다면 가운데 회로처럼 구성할 수 있겠지요. 그리고 스위치를 접지하는 라인은 전선이 전류를 견딜 수 있다면 하나로 통합해도 문제가 없습니다. 따라서 아래 그림의 오른쪽처럼 회로를 변경할 수 있습니다.

그림 1. 스위치 병렬 연결

이번에 키보드를 만들때 사용할 아두이노 호환보드는 digitalRead()로 전압을 읽을 수 있는 GPIO 단자가 18개 뿐입니다. 모든 단자를 입력을 감지하는데 사용한다면, 위 방식으로 회로를 구성할 경우 총 18개의 스위치를 사용할 수 있습니다. 하지만 이번에 만들 키보드는 총 90개의 스위치를 사용해야 하기 때문에, 더 많은 스위치를 사용할 수 있도록 다른 방식으로 회로를 구성해보도록 합시다.

 

매트릭스 구성

그림 2. 스위치 매트릭스

먼저 위 회로에서 하나의 접지 라인에 2개의 스위치를 연결한 것 처럼, 각 행마다 2개의 스위치를 연결해봅시다. 하지만 한 행에 연결된 스위치 중 어떤것을 눌러도 똑같이 접지 라인으로 연결되기 때문에 어떤 스위치를 눌러졌는 지 구분할 수 없습니다. 그렇다면 각 열 라인을 구분해주기 위해, 먼저 행 라인처럼 접지단자가 아닌 GPIO 단자에 연결해줍니다. 그리고 열 라인을 연결해준 단자의 모드를 Output으로 설정합니다. 그러면 digitalWrite()함수를 통해 Low를 출력하면 0V가 공급되므로 접지에 연결한 것 처럼, High를 출력하면 5V가 공급되므로 VCC에 연결한 것 처럼 생각해 각 열 라인을 구분할 수 있습니다. 스위치 입력을 감지하고자 하는 열을 Low로 나머지 열을 High를 설정하고 각 행의 전압을 읽는 것으로 해당 열의 스위치 입력 상태를 감지할 수 있습니다. 아래 표는 열 1이 Low, 열 2가 High 일 때 스위치 입력에 따라 각 행의 전압을 digitalRead()로 읽은 결과를 정리한 것입니다.

스위치 11 스위치 12 스위치 21 스위치 22 행 1 행 2
1 1
0 1
1 1
1 0
1 1
0 1
0 0
0 1
1 0
1 1
1 0
0 0
0 0
0 0
0 0
0 0

스위치 11일 눌러진 경우 행 1이 0으로, 스위치 21이 눌러진 경우 행 2가 0이 되며, 스위치 12와 스위치 22는 하나씩 눌러진 경우 결과에 아무런 영향을 주지 않습니다. 하지만 두 스위치가 동시에 눌러진 상태로 다른 스위치를 누를 경우 문제가 발생하는데, 누르지 않은 스위치가 눌러진 것 처럼 원하지 않은 결과가 나오는 것입니다.

 

다이오드 추가

이를 보통 고스트 키 현상이라 부릅니다. 원인은 스위치 입력에 따라 회로의 다른 경로를 우회해 전류가 흘러가 마치 특정 스위치가 눌러진 것 처럼 전류가 흐르기 때문입니다. 예를 들어 아래 회로에서 스위치 21을 누른다면 Row 2 → SW21 → Col 1 순으로 전류가 흐릅니다. 또한 스위치 11, 스위치 12, 스위치 22가 눌러진 경우라면 Row 2  SW22  SW12  SW11  Col 1 순으로 전류가 흐릅니다. 두 경우 모두 중간 경로는 다르지만 Row 2에서 Col 1로 전류가 흐르게 된다는 점은 같습니다. 때문에 Col 1이 Low일 때 Row 2가 0이므로 SW21가 눌러져 있다라고 판단하는 것입니다.

그림 3. 고스트 키 현상과 해결법

해결하는 방법은 간단한데 우회해서 전류가 흐르지 않도록 다이오드를 추가해 주는 것입니다. 다이오드는 전류를 한쪽 방향으로만 흐르게 해주는 소자이므로 스위치 앞이나 뒤에 추가하면 전류가 우회해서 흐르지 못하게 할 수 있습니다. 위 그림의 오른쪽 회로를 보면 Row 2에서 흐르기 시작한 전류가 SW12 앞에 있는 다이오드에 의해 차단되 Col 1로 흐르지 못하는 것을 알 수 있습니다. 추가로 Col 2에서 Col 2로 저항 없이 연결되어 과전류로 인해 보드가 망가지는 것 도 방지할 수 있습니다. 과전류는 보드와 Col 라인 사이에 100~200Ω 정도의 저항을 연결해 주는 것으로 해결할 수 있지만 다이오드를 추가해 주었다면 생략해도 무방합니다.

 

여기까지 구성한 회로를 9행 9열로 확장하면 최대 81(=9x9)개의 스위치를 사용할 수 있습니다. 키패드나 포커배열 키보드라면 이정도로 충분하지만 사용할 수 있는 스위치가 아직 90개가 안되기 때문에 한단계 더 확장해 보도록 합니다.

 

스위치와 합성저항

지난 글에서도 설명했듯이 아두이노로 스위치의 상태를 판별하는 방법은 스위치에 걸린 전압을 측정하는 것입니다. 정확히는 스위치를 저항으로 간주하고 스위치 앞 지점과 지면(GND) 사이에 걸리는 전압을 측정하는 것입니다. 매트릭스 회로라면 특정 행과 특정 열 사이에 걸리는 전압을 측정하는 것입니다. 이때 측정되는 전압은 저항값에 따라 달라지며, 저항값은 스위치와 저항을 적절하게 연결하는 것으로 바꿀 수 있습니다. 아래 그림은 위 회로에서 스위치와 다이오드를 병렬연결해서 2개로 늘려주고 저항을 추가한 회로입니다.

그림 4. 스위치와 저항의 병렬연결로 연결한 회로

 

위 회로는 불필요하게 저항이 많이 들어가 키보드에 배치할 공간이 부족하므로 같은 크기의 저항을 사용하는 라인을 통합해 정리해 주었습니다.

그림 5. 같은 저항을 사용하는 라인을 통합한 회로

 

그리고 키보드에 사용할 수 있도록 스위치별로 분리해 한번 더 정리해 주었습니다.

그림 6. 스위치별로 분리한 회로

 

위 회로는 이제 행의 전압을 읽을 때 digitalRead()가 아니라 analogRead() 함수를 사용해야 하며, analogRead() 함수는 모든 포트에서 사용할 수 없기 때문에, 각 행 라인은 아날로그 읽기를 지원하는 포트에 연결해 주어야 합니다. 핀아웃을 확인해 보면 4, 6, 8, 9, 10, 18, 19, 20, 21의 총 9개 포트에서 아날로그 읽기를 지원하고 있습니다. 열 라인은 GPIO 포트 아무곳에나 연결해도 상관없지만 행 라인은 반드시 아날로그 포트에 연결해 주시기 바랍니다. 미지원 포트에 연결한 경우 analogRead()로 전압을 읽어도 무의미한 쓰레가 값을 반환합니다.

 

완성

그림 7. 완성된 회로도

위 그림은 최종적으로 사용할 회로도입니다. 실제로 소자를 배치할 모습과 최대한 비슷하게 그렸습니다. 최대 108(= 6행 x 6열 x 3저항)개의 스위치를 사용할 수 있는 회로입니다. 저항의 크기는 구매할 수 있는 것들 중에서 적당한 것으로 골랐습니다.

키보드 스위치 회로를 만들기 전에 우선 간단하게 관련 이론부터 알아보도록 합시다.

 

전압 분배 법칙

아래 회로에 5V의 전압을 공급해 주면 왼쪽에서부터 전류가 흐르기 시작해 저항1과 저항2를 거쳐 오른쪽에 접지된 부분까지 도달합니다. 이때 저항1의 왼쪽에서 전압을 측정하면 5V(공급전압)가 저항2의 오른쪽에서 측정하면 0V(접지)가 나옵니다. 이때 저항1과 저항2의 사이에서 전압을 측정하게 되면 얼마가 나오는 지를 설명해주는 것이 전압 분배 법칙입니다.

 

그림 1. 2개의 저항을 직렬 연결한 모습

결론부터 말하면 회로 전체 저항에서 저항2가 차지하는 비율에 비례한 전압이 측정됩니다. 예를들어 R1이 20Ω, R2가 30Ω이라면 저항2에는 V(in) x {30/(20+30)} = 5V x (3/5) = 3V의 전압이 걸리게 됩니다. 키보드 회로에서는 이 V(out)의 값을 측정하는 것으로 스위치가 눌러졌는지를 확인합니다.

 

스위치 연결

이제 한 단계 더 나아가 위 회로에서 저항2 대신에 스위치를 연결해 봅시다. 전압을 측정하기 위해 V(out) 부분을 아두이노의 GPIO 단자 중 한곳에 연결해 줍니다. 연결한 단자의 모드를 Input으로 변경하면 아두이노 함수를 사용해 전압을 읽을 수 있습니다. 마지막으로 V(in) 부분을 아두이노의 VCC 단자에, 접지 부분을 GND 단자에 연결해주면 회로 구성이 끝납니다. 참고로 VCC와 저항1에 해당하는 부분은 매우 빈번하게 사용되므로, 편의를 위해 아두이노 칩 내부에 구성되어 있습니다. V(out) 부분이 연결된 단자의 모드를 Input_Pullup 으로 변경하는 것으로 아래 회로에서 회색 부분을 생략할 수 있습니다. 이때 저항1을 풀업저항이라 부르며 5V보드에서 보통 10k~20kΩ 정도의 저항이 사용되고 있습니다.

 

그림 2. 저항2 대신 스위치를 연결한 모습

위 회로를 구성한 다음 아두이노로 전압을 읽으면, 스위치가 열려있을 때는 5V, 닫혀있을 때는 0V로 측정됩니다. 이는 스위치가 열려 있을 때는 무한대에 가까운 매우 큰 값을 가진 저항으로 간주할 수 있어 상대적으로 크기가 매우 작은 저항1을 무시하면 1 x VCC가 되기 때문이며, 스위치가 닫혀있을 때는 스위치 자체의 저항이 매우 작아 0으로 간주할 수 있기 때문에 0 x VCC가 되기 때문입니다.

 

전압 측정

지난 글에서 만든 키패드는 열에 해당하는 파란 선들을 Input_Pullup 모드로, 행에 해당하는 빨간 선들을 Output 모드로 설정한 다음 스위치의 상태를 읽었습니다. 이때 digitalRead() 함수로 읽은 결과값으로 스위치를 눌렀을 때 0, 누르지 않았을 때 1을 얻을 수 있었습니다. 이는 아두이노 내부적으로 특정 전압을 기준으로 결과를 0과 1로 구분하여 돌려주기 때문입니다. 제가 사용하는 보드의 경우 3.5V 정도를 기준으로 넘으면 1, 아니라면 0으로 구분하고 있었습니다. 이 기준값은 내부 회로구성에 따라 변하기 때문에 보드마다 차이가 있을 수 있습니다.

 

도표 3. 분해성능에 따른 출력값 분포

회로구성에 따라 조금더 세밀하게 전압을 구할수도 있는데, 한번 측정한 전압을 기준을 바꿔가며 반복해서 측정해 나간다면 한 단계를 거칠때 마다 해상도가 2배씩 늘어나게 됩니다. 1번 측정했을 때 해상도는 2, 2번 측정하면 2x2=4, 3번 측정하면 2x2x2=8이 됩니다. 즉 n번 측정을 했을 때, 해상도는 2^n이 되는 것입니다. 실제로 아두이노는 1024단계로 구분된 전압을 구할 수 있고 이를 analogRead() 함수를 통해 지원합니다. 엄밀하게는 10bit Digital Read라고 해야 하겠지만 측정 단위기 충분히 세밀하기 때문에 일반적인 용도로 사용한다면 아날로그로 간주해도 문제가 없습니다.

 

전압의 측정 범위는 기본적으로 보드의 작동 전압을 기준으로 하기 때문에, 5V 보드에서는 0~5V, 3.3V 보드에서는 0~3.3V의 범위에서 전압을 측정합니다. 추가로 Analog Reference 단자에 xV의 전압을 입력하면 0~xV 범위에서 전압을 측정할 수도 있습니다. 예를 들어 Analog Reference 단자에 4V의 전압을 입력하고 analogRead() 함수를 사용하면 0~4V 범위에서 4V/1024≒0.0039V=3.9mV 단위로 전압을 측정합니다. 이 때 2.7V의 전압을 analogRead() 함수로 읽으면 반환값으로 691을 돌려줍니다. 만약 0~5V 범위에서 측정했다면 측정 단위는 5V/1024≒0.0049V=4.9mV가 되기 때문에 반환값은 553이 됩니다. 실제로는 노이즈 등으로 어느정도 측정오차가 발생해 조금씩 결과값이 달라지기도 합니다.

 

합성저항

digitalRead() 함수는 전압의 상태를 2단계로 구분하기 때문에 스위치를 2개 이상 연결하면 어떤 스위치가 눌러졌는 지 구분할 수 없습니다. 하지만 analogRead() 함수를 사용하면 1024단계로 전압을 구분하므로 여러개의 스위치를 연결해도 측정된 전압의 차이를 통해 어떤 스위치가 눌러졌는지 구분할 수 있습니다. 전압의 차이는 스위치를 이용해 저항을 합성시키는 것으로 만들 수 있습니다.

 

그림 4. 저항의 직렬연결

스위치1 스위치2 스위치3 스위치4 합성저항
○ or ● ○ or  ○ or  0
○ or  ○ or  R3
○ or  R3 + R4
R3 + R4 + R5

 

먼저 저항을 직렬로 연결한 경우입니다. 왼쪽부터 스위치를 차례대로 하나씩 눌렀을 경우, 각 저항의 크기가 단순히 더해져 합성저항이 점점 커져가는 것을 확인할 수 있습니다. 2개 이상을 눌렀을 경우는 가장 왼쪽에 있는 스위치만 누른 것과 동일한 결과가 나옵니다. 예를들어 스위치2와 스위치3을 동시에 눌렀을 경우, 저항4와 스위치3을 직렬연결한 것에 스위치2를 병렬연결한 것으로 간주할 수 있는데 스위치의 저항이 0Ω이라 할 수 있으므로 부분 합성저항은 0Ω이 되어 결국 저항3만 연결한 경우와 같게 됩니다. 즉 동시에 여러 키를 눌러도 이를 인식할 수 없습니다. 반면 합성저항을 구하는 방법이 단순해 쉽게 크기를 조절할 수 있으므로, 측정되는 전압의 간격이 4.9mV가 되도록 만들면 이론적으로 하나의 단자로 1023개의 스위치 중 어느것이 눌러졌는지 확인할 수 있습니다. 실제로는 측정오차를 고려해야 하기 때문에 수는 줄어듭니다만 그래도 10개 정도는 여유롭게 연결할 수 있습니다.

 

그림 5. 저항의 병렬연결

스위치1 스위치2 스위치3 합성저항 예시
R3 60
R4 40
R5 30
(R3 x R4) / (R3 + R4) 24
(R3 x R5) / (R3 + R5) 20
(R4 x R5) / (R4 + R5) 17
(R3 x R4 x R5)
/ (R3 x R4 + R3 x R5 + R4 x R5)
11

 

다음으로 저항을 병렬로 연결한 경우입니다. 직렬로 연결한 경우와는 다르게 어떤 식으로 스위치를 눌러도 합성저항이 모두 다르게 나오는 것을 확인할 수 있습니다. 예시란은 저항3~저항5가 각각 60, 40, 30일 경우 합성저항이 어떻게 되는지 계산한 결과입니다. 합성저항의 크기가 너무 가까우면 측정오차로 인해 스위치 입력을 정확히 구분할 수 없는 경우가 생기므로, 실제로 사용할 경우 단자 하나에 스위치 3개 정도가 한계라고 생각합니다. 하지만 스위치의 동시입력을 구분할 수 있기 때문에 키보드에 적용하기에 직렬연결보다 적절합니다.

단순히 보강판을 설계할 뿐이라면 종이와 펜만 있으면 충분하지만, 업체에 주문제작을 의뢰하기 위해서는 보통 2D 도면 파일이 필요합니다. CAD 프로그램이나 Adobe의 일러스트레이터로 만든 설계도를 보내주면 대부분 문제 없습니다. 저는 무료 2D CAD 프로그램인 QCADCAM으로 보강판을 설계한 다음 .dxf 형식으로 저장한 파일로 의뢰해서 설계도와 동일하게 제작된 물건을 받았습니다.

 

키 레이아웃처럼 보강판 역시 간단하게 설계해주는 사이트가 존재합니다. (링크: http://www.keyboardcad.com)

지난 글에서 </>RawData로 저장한 내용을 위 사이트에 붙여넣고 몇가지 옵션을 선택해 주기만 하면 거의 완성된 보강판 설계도면을 다운로드 할 수 있습니다. 아래 그림은 해당 사이트에서 보강판 설계도를 생성한 화면입니다.

사진 1. 자동으로 생성된 보강판 도면

별다른 설명이 필요 없을 정도로 간단한 작업입니다만, 먼저 커스텀시에 필요한 설정값에 대해 알아보도록 합시다.

Switch Cutout Type

스위치 구멍의 모양을 지정합니다. Square는 한 변이 14mm인 정사각형 형태입니다. 기본적인 형태이고 가장 안정적으로 스위치가 장착됩니다. Side Notches의 경우 보통 기판에 스위치가 결합된 상태로 스위치 상부 하우징을 분리하기 위해 스위치 구멍 좌우로 홈을 파준 형태입니다. 파여진 홈으로 투을 집어넣어 스위치 상부 하우징을 분리합니다. 스위치 좌우를 지지해주는 부분이 적어 흔들림이 발생할 수 있습니다. H Notches는 사이드 노치의 단점을 보완한 형태로 정확히 필요한 부분함 홈을 파냈기 때문에 가운데 부분이 남아있어 좌우 흔들림을 잡아줍니다. 대신 형상이 복잡해진 만큼 가공 시간과 단가가 올라갑니다.

Stabilizer Cutout Type

스테빌라이저 장착 구멍입니다. 대부분의 경우 체리식을 사용하므로 체리식을 선택하시면 됩니다. 기판에 장착하는 체리식 스테빌라이저는 보강판에 장착하는 형태보다 구멍이 작으므로 역시 체리식을 선택해 주시면 됩니다. Costar는 한국에서 흔히 마제식으로 불리는 형태입니다.

사진 2. 스테빌라이저의 장착 방식

Plate Border Width

보강판 테두리 두께입니다. 0을 입력할 경우 보강판 테두리와 키캡의 외각선이 일치하게 됩니다. 기본값인 2.5mm를 지정한 경우 테두리의 가장 얇은 부분(스위치 구멍이 있는 부분)이 5mm가 됩니다.

Kref

톱날 두께를 말합니다. 나무를 자를 때 톱날 두께만큼 재료가 줄어드는 것을 보정하기 위해 입력합니다. 아크릴 레이저 커팅의 경우 2~3T라면 0.1mm, 5T라면 0.2mm로 지정해 주시면 대부분 문제없습니다.

Grid Spacing

키캡 사이의 간격, 즉 1u의 크기를 지정합니다. 표준 레이아웃에서 1u는 3/4inch(=19.05mm)이기 때문에 일반적으로 판매되고 있는 기판들 역시 19.05mm 간격으로 제작됩니다. 해당 기판을 사용하면서 보강판을 19mm 간격으로 제작할 경우 기판과 보강판의 구멍이 맞지 않아 스위치 결합이 불가능하므로 19.05mm를 선택해줍니다. 기판이 없거나 직접 제작하는 경우, 숫자가 깔끔하게 나와서 알아보기 쉬운 19 mm를 선택하셔도 문제없습니다.


이제 Square, Cherry, Default, 0.1mm, 19mm를 선택하고 Submit 버튼을 누른 다음 생성된 도면파일(.dxf)을 다운로드 받아 CAD 프로그램으로 마무지를 지어줍니다. 테두리를 둥글게 하고 외각 지지대 부분과 아두이노를 올려둘 부분까지 만들어 두었습니다.

그림 3. 캐드 프로그램으로 완성한 보강판 도면

지지대 외에도 스테빌라이저 부분도 파손이 우려되 얇게 돌출된 부분을 이어주고, 스테빌라이저의 돌기 한쪽을 제거하고 장착하기로 했습니다.

 

그림 4. 카일 박스축 스위치의 치수
그림 5. 보강판 두께와 스위치 홀의 크기

지지대 설계시 주의할 점은 보강판 상단에서 바닥면 까지 최소 9mm가 되도록 해야 한다는 것입니다. 스위치에서 나오는 다리 부분이 보강판 상단면에서 8.3(5.0+3.3)mm 이므로 보강판이 휘면서 바닥이 긁히지 않도록 하려면 10mm 이상을 확보하시길 권해드립니다. 또한 보강판 두께가 1.9T가 넘어갈 경우 스위치의 고정 돌기부분에 의한 탄력으로 스위치가 빠져나올 수 있으니 글루건이나 순간 접착제 등으로 고정하거나 돌기와 닿는 보강판 부분을 경사지게 갈아줄 필요가 있습니다. 또한 체리식 보강판 장착 스테빌을 사용할 경우 보강판 두께가 2T를 넘어가면 철심 부분과 간섭해서 키감에 악영향을 미치니 보강판 두께는 2T 이하로 만드실 것을 권합니다.

 

위 도면으로 2T 아크릴로 업체에 주문하고 받은 보강판입니다. 보강판~지지대의 높이가 6mm 이므로 10mm가 안되지만, 종이박스로 만든 지지대로 여러 높이와 경사로 사용해보고 알맞은 정도롤 알아보고 추후 별도로 다리 부분을 만들어 완성시킬 예정입니다. 이제 다음 단계는 스위치를 장착하고 배선하는 것입니다.

사진 6. 완성된 아크릴 보강판

 

PS. 요즘은 화관법/화평법 영향으로 개인용으로 판매하는 아크릴 접착제를 구하기가 굉장히 힘든 관계로, 다음부터는 보강판을 설계할 때 볼트/너트를 사용해 결합하는 방식으로 만들어야 할 것 같네요. 생각치도 못한 곳에서 발목이 잡혔습니다.

키보드라 하면 사용할 목적에 맞게 키들을 배열해놓은 판을 말합니다. 따라서 제일 먼저 해야 할 일은 용도에 맞는 배치를 결정하는 것입니다. 하지만 배열이 그다지 중요하지 않은 경우, 예를 들면 너무 마음에 드는 키캡이 있어서 키캡과 어울리는 키보드를 만들고자 하는 경우에는 키캡에 맞춰서 레이아웃을 결정할 수도 있습니다.

 

표준 배열

일반적으로 가장 많이 사용되는 배열은 US 표준 104키 배열이고, 키캡도 표준 배열에 맞춰서 주로 생산/판매되고 있습니다. 윈키리스라고 하는 104키에서 윈도우키 2개와 메뉴키 1개를 제외한 101키 배열도 있습니다. 윈도우가 등장하기 전에 주로 사용한 배열입니다. 한글 윈도우에서 101/104키 배열 키보드를 사용한다면 키보드 설정에서 101/104키 호환 모드로 변경해 주면 키보드 가운데 있는 Alt 키와 Ctrl 키를 한자, 한/영 키로 맵핑해서 사용할 수 있습니다. 그래서 국내에서 사무용으로 판매되는 키보드는 대부분 스페이스 키 좌우로 한자, 한/영 키를 추가한 103/106키 배열을 주로 사용하고 있습니다. 이 외에도 각 나라의 사정에 맞춘 유럽식 102/105키나 일본식 106/109키 등의 배열도 존재합니다.

그림 1. US 표준 104키 배열

 

비표준 배열

표준 배열을 조금 변형한 배열 외에도, 오른쪽 키패드 부분을 제외한 87키 배열을 텐키리스 배열(그림 1의 파랑+주황)이라 하고, 텐키리스에서 최상단 펑션키들과 우측 내비게이션 키들을 제외한 60키 배열을 포커 배열(그림 1의 파랑)이라 부르기도 합니다. 커스텀 제품이 아니더라도 제조사별로 표준/텐키리스/포커 배열을 수정한 제품을 판매하기도 합니다.

그림 2. 레오폴드 FC660M의 키 배열

 

키캡 사이즈

가장 작은 정사각형 키를 나란히 배열했을 때, 두 키 사이의 간격을 1u라고 합니다. 예를 들면 'A' 키는 1u 타입의 키이고 'Ctrl'은 1.25u, 'Enter'는 2.25u 타입의 키입니다. 위의 그림 2에 표시된 'Win' 키와 오른쪽 'Shift' 키는 표준 배열과 사이즈가 다른 키를 사용하고 있습니다. 'Win'키가 1.25u에서 1u로, 오른쪽 'Shift'키가 2.75u에서 2.25u로 줄어들었습니다. 따라서 표준 배열에 맞는 사이즈의 키들만 제공하는 키캡 세트를 구입하면 문제가 발생하니 키캡 구매 시 주의할 필요가 있습니다. 그래서 커스텀 키보드용으로 판매하는 키캡 세트는 비표준 배열에도 사용할 수 있도록 다양한 사이즈의 추가 키들의 포함한 세트를 팔기도 합니다.

사진 3. 표준 104키 외에 20개의 추가 키가 포함된 키캡 세트

 

키캡 프로파일

키캡 구매 시에 주의할 점은 키캡 사이즈 외에도 스탭스 컬처 2방식이 적용된 프로파일을 사용하는 경우 키의 행 이동이 제한된다는 점입니다. 장시간 키 입력 시 손가락의 피로감을 줄이기 위해 키 위치별로 높이나 경사를 다르게 하는 것을 스탭스 컬처 방식이라고 합니다. 스탭스 컬처 1의 경우 동일한 형태의 키를 사용하지만 스위치가 설치된 기판 자체를 휘게 하거나 하나의 기판을 여러 개로 나눠서 계단식으로 만든 방식을 말합니다. 제작 난이도가 높아서 생산단가가 높기 때문에 지금의 거의 사용되지 않는 방식입니다. 대신 기판은 평면이지만 키캡을 행별로 다르게 만드는 방식을 스탭스 컬처 2라고 합니다. 요즘 판매되는 대부분의 제품에 적용되는 방식입니다. 물론 스탭스 컬처가 적용되지 않은 키캡도 있습니다. XDA와 DSA 프로파일이 대표적입니다. 펜타그래프 방식의 노트북 키보드처럼 키캡의 높이가 낮고 상단의 높이가 거의 일정하다는 것이 특징입니다. 이런 키캡을 사용하면 행 이동이 자유로워서 여분의 키캡을 활용하기 좋다는 장점이 있습니다.

그림 4. 대표적인 키캡 프로파일

 

키캡 각인

키캡의 사이즈와 프로파일을 정했으면 이제 남은 것은 각인입니다. 키캡에 글자를 인쇄하는 방식에는 염료승화나 레이저, 실크 인쇄, 이중사출 같은 것들이 있습니다. 또 인쇄 위치에 따라 정각(상단)이나 측각(정면), 무각(각인 없음)이 있습니다. 사실 키캡을 선택한 시점에서 각인도 거의 결정된 것이나 마찬가지입니다. 다만 무각으로 제작된 키캡에 레이저로 각인을 새기는 경우 정각/측각/무각을 선택할 수 있기도 합니다. 하지만 키보드에 존재하지 않는 키를 사용하는 싶은 경우, 예를 들어 특정 키 조합이나 멀티미디어 키, 매크로, 타이머, 다른 하드웨어 제어용으로 사용할 경우 고려해 볼 만한 방식은 아래와 같습니다.

  • 투명 라벨지에 인쇄해서 붙인다
  • 다른 색의 무각 키캡을 사용한다
  • 기존 키캡을 염색하거나 도색한다
  • 레이저로 직접 각인을 새긴다
  • 레진이나 목재 등을 사용하여 키캡을 직접 만든다

 

커스텀 레이아웃 만들기

우선 이번에 제작할 키보드에 사용할 키캡은 키캡계의 교복이라 부르기도 하는 분필 키캡을 사용하기로 했습니다. 정확히는 OEM 프로파일이 적용된 PBT 소재의 104키 표준 배열용 무각 분필 키캡입니다.

사진 5. OEM 프로파일 PBT 분필 키캡

위 키캡을 측면의 형태가 같은 키들끼리 색은 색으로 표시하면 아래 그림 6과 같습니다. 상단부터 R1, R1, R2, R3, R4, R4순으로 나열되어 있습니다. 같은 R1 - R1 끼리 키를 바꾸는 것은 아무 문제가 없지만, R1 - R4를 바꿀 경우 키캡의 높이가 달라져 상당한 이질감이 느껴지니 지양하는 것이 좋습니다.

그림 6. 스탭스 컬쳐 2방식의 키캡 구분

아래 그림 7은 행 위치에 주의하며 표준 배열을 수정한 것입니다. 여기서 오른쪽 키패드 부분은 사용하지 않을 것이므로 이전 글에서 키패드를 만드는 데 사용했습니다.

그림 7. 수정한 키 배열

아래 그림 8은 제가 실제로 사용할 배열입니다. 무각 키캡이므로 실제 키캡과 동일하게 각인을 지우고 색을 지정해 주었습니다. 여기까지 완성했으면 우측 상단에 Download 버튼을 눌러서 작업한 내용을 JSON 파일로 저장하거나, 하단의 </>RawData 탭의 내용을 복사해서 텍스트 파일로 저장해 줍니다. 이제 다음은 보강판 설계입니다.

그림 8. 완성된 커스텀 배열


참고링크

국제표준 배열 : https://en.wikipedia.org/wiki/ISO/IEC_9995

키보드 레이아웃 편집기 : http://www.keyboard-layout-editor.com

본격적으로 키보드 만들기에 들어가기 전에, 간단한 키패드를 만들어 보면서 전체적인 흐름을 알아보도록 합시다.

 

1. 레이아웃 디자인과 키캡 고르기

우선 자신이 만들 키보드의 키 배치를 생각해보고, 사용할 키캡을 선택합니다.

표준 배열을 사용한다면 대부분의 키캡을 사용할 수 있지만, 자신만의 배열을 사용할 거라면 그 배열을 사용할 수 있는 키캡을 골라줍니다. 해당 배열에 필요한 키가 없다면 다른 키캡을 고르거나 키캡에 맞춰 배열을 수정해줘야 합니다.

 

아래 사이트에서 간단하게 키보드 배열을 구성해보고, 이미지나 데이터 파일로 저장하거나 나중에 불러올 수 있습니다.

http://www.keyboard-layout-editor.com/

그림 1. 분필 키캡을 사용한 표준 키패드 배열 (좌: 정각 / 우: 무각)

 

2. 보강판 설계

레이아웃을 결정했으면 이제 스위치를 고정해줄 보강판을 설계할 차례입니다. 커스텀 키보드를 만든다면 일반적으로 일러스트레이터나 캐드로 도면을 만들어 가공업체에 제작을 의뢰합니다. 하지만 이번에는 오래 사용할 키패드가 아니라 연습용으로 만드는 키패드이기 때문에 적당히 집에 있는 피자박스로 보강판을 만들겠습니다. 보강판 설계를 끝내면 하우징 설계에 들어갈 순서입니다만, 이번에는 간단하게 보강판을 하우징 일체형으로 만들어 사용합니다.

그림 2. 보강판 도면
사진 3. 완성된 보강판겸 하우징

 

3. 회로 설계

보강판 설계를 끝냈으면 이제 스위치와 컨트롤러를 연결해주는 회로를 설계할 차례입니다. 이번에는 PCB를 제작하지 않고 스위치에 직접 납땜할 것이기 때문에 회로설계만 하고 아트웍과 PCB 제작은 생략합니다. 간단한 5행 4열 매트릭스 구성이며 고스트 키 방지를 위해 스위치마다 다이오드를 하나씩 달아주었습니다.

그림 4. 키패드 회로도

 

4. 준비물 구입

회로 설계까지 끝났다면 이제 필요한 재료들을 구입합니다. 아두이노를 분리할 수 있도록 만들려면, 전선 대신 핀헤더와 Female 커넥터가 달린 점퍼선을 구입하시면 됩니다. 사용하지 않을 때 분리해서 다른 용도로 사용하거나 고장났을 때 수리하기 쉽지만, 부피가 조금 커져서 내부에 더 많은 공간을 필요로 합니다.

 

재료 : 스위치, 키캡, 아두이노, 다이오드, 전선, 보강판(이번에는 골판지)

선택: 핀헤더, Female 커넥터

도구 : 인두기, 실납, 니퍼

사진 5. 준비물 (스위치, 키캡, 아두이노, 다이오드, 전선)

 

5. 보강판과 스위치, 키캡 결합

준비물이 모두 갖춰줬으면 이제 부품들으 조립해줍니다. 우선 스위치에 키캡을 끼워준 다음, 보강판에 스위치를 결합합니다. 그리고 보강판을 접어서 테이프로 마무리합니다.

사진 6. 키캡, 스위치, 보강판을 결합한 모습
사진 7. 키패드 안쪽

 

6. 스위치 회로 구성

이제 스위치와 아두이노를 연결할 회로를 만들어줍니다. 작업할 때는 아래쪽에서 위를 바라보면서 작업하기 때문에 회로도와 좌우가 반대로라는 것에 주의하면서 스위치를 전선에 연결해줍니다. 다이오드의 방향이 행→열인지, 열→행인지는 상관없지만 반드시 모두 동일한 방향으로 연결해줘야 정상 작동합니다. 다이오드 방향에 주의하면서 작업해주세요.

사진 8. 회로 연결이 완료된 모습

 

7. 아두이노와 키패드 연결

이제 키패드와 아두이노를 연결할 차례입니다. 필요하다면 아두이노에 핀헤더를 달아주고 아니라면 전선을 직접 납땜해줍니다. 이번에는 핀헤더를 달아주었습니다.

사진 9. 아두이노 마이크로 호환보드에 핀헤더를 달아준 모습

 

키패드 회로와 연결할 아두이노 핀은 입출력으로 사용할 수 있는 핀이여야 합니다. 정확한 핀 구성은 아두이노 홈페이지나 호환 보드를 구입한 사이트의 상세페이지에 나와있습니다. 아래 그림은 이번에 구입한 호환 보드의 핀 구성입니다. 4~7번 핀에 Col 1~4를 연결해 주었고, 14~19번 핀에 Row 1~5를 연결해 주었습니다.

그림 10. 아두이노 호환보드의 핀 구성

 

회로의 노출된 부분과 아두이노가 합선되지 않도록, 가림판을 하나 끼워주는 걸로 하드웨어 구성이 모두 끝났습니다.

사진 11. 아두이노와 키패드를 연결한 모습

 

8. 아두이노 IDE 설치와 펌웨어 프로그래밍

이제 하드웨어를 완성했으니 키보드로 사용하기 위한 펌웨어를 만들어줄 차례입니다. 먼저 아두이노 홈페이지에서 아두이노 IDE를 다운받아 설치한 다음 실행합니다. PC와 아두이노를 USB로 연결하고 아두이노에 불이 들어오는 것을 확인하면, 펌웨어 제작을 위한 준비는 모두 끝났습니다.

https://www.arduino.cc/en/software

 

아래는 제가 작성한 스케치 코드입니다. 아두이노 IDE에 아래 코드를 붙여놓고 업로드하시면 바로 키패드를 사용하실 수 있습니다. 해당 코드는 아두이노에 저장되기 때문에 다른 PC에 연결해도 문제없이 작동합니다.

// 키보드 라이브러리를 사용한다
#include <Keyboard.h>

// 사용하는 핀번호를 지정한다
#define PIN_ROW_1 19
#define PIN_ROW_2 18
#define PIN_ROW_3 15
#define PIN_ROW_4 14
#define PIN_ROW_5 16
#define PIN_COL_1 7
#define PIN_COL_2 6
#define PIN_COL_3 5
#define PIN_COL_4 4

// 사용할 배열의 크기를 지정한다. 5행 x 4열 = 20
#define MATRIX_SIZE 20

// PC로 전송할 키코드
const byte keycode[MATRIX_SIZE] = {219, 220, 221, 222,   // N / * -
                                   231, 232, 233,   0,   // 7 8 9
                                   228, 229, 230, 223,   // 4 5 6 +
                                   225, 226, 227,   0,   // 1 2 3
                                   234,   0, 235, 224};  // 0   . E

// 스위치 스캔 결과를 기록할 배열
bool bufferA[MATRIX_SIZE];
bool bufferB[MATRIX_SIZE];

// 어떤 배열에 이전/현재 결과가 들어있는지 지정한다
bool *prevBuffer = &bufferA[0];
bool *curBuffer = &bufferB[0];
bool *tempBuffer;

// 채터링 현상 방지용 지연시간을 지정한다
#define DEBOUNCE_DELAY 20

// 키별로 마지막으로 상태변화가 일어난 시간을 기록할 배열
unsigned long lastChange[MATRIX_SIZE];
unsigned long curMillis;


// 아두이노 초기설정
void setup() {
  // 스캔 결과를 기록할 배열을 초기화한다 (1: 대기상태, 0: 키 눌러짐)
  for (int i = 0; i < MATRIX_SIZE; i++) {
    bufferA[i] = 1;
    bufferB[i] = 1;
  }

  pinMode(PIN_ROW_1, OUTPUT);
  pinMode(PIN_ROW_2, OUTPUT);
  pinMode(PIN_ROW_3, OUTPUT);
  pinMode(PIN_ROW_4, OUTPUT);
  pinMode(PIN_ROW_5, OUTPUT);

  digitalWrite(PIN_ROW_1, HIGH);
  digitalWrite(PIN_ROW_2, HIGH);
  digitalWrite(PIN_ROW_3, HIGH);
  digitalWrite(PIN_ROW_4, HIGH);
  digitalWrite(PIN_ROW_5, HIGH);

  pinMode(PIN_COL_1, INPUT_PULLUP);
  pinMode(PIN_COL_2, INPUT_PULLUP);
  pinMode(PIN_COL_3, INPUT_PULLUP);
  pinMode(PIN_COL_4, INPUT_PULLUP);
}


// 아두이노 반복실행 코드
void loop() {
  // 스위치별로 입력상태를 확인한고 결과를 버퍼에 기록한다
  digitalWrite(PIN_ROW_1, LOW);
  curBuffer[0] = digitalRead(PIN_COL_1);
  curBuffer[1] = digitalRead(PIN_COL_2);
  curBuffer[2] = digitalRead(PIN_COL_3);
  curBuffer[3] = digitalRead(PIN_COL_4);
  digitalWrite(PIN_ROW_1, HIGH);
  digitalWrite(PIN_ROW_2, LOW);
  curBuffer[4] = digitalRead(PIN_COL_1);
  curBuffer[5] = digitalRead(PIN_COL_2);
  curBuffer[6] = digitalRead(PIN_COL_3);
  //curBuffer[7] = digitalRead(PIN_COL_4);
  digitalWrite(PIN_ROW_2, HIGH);
  digitalWrite(PIN_ROW_3, LOW);
  curBuffer[8] = digitalRead(PIN_COL_1);
  curBuffer[9] = digitalRead(PIN_COL_2);
  curBuffer[10] = digitalRead(PIN_COL_3);
  curBuffer[11] = digitalRead(PIN_COL_4);
  digitalWrite(PIN_ROW_3, HIGH);
  digitalWrite(PIN_ROW_4, LOW);
  curBuffer[12] = digitalRead(PIN_COL_1);
  curBuffer[13] = digitalRead(PIN_COL_2);
  curBuffer[14] = digitalRead(PIN_COL_3);
  //curBuffer[15] = digitalRead(PIN_COL_4);
  digitalWrite(PIN_ROW_4, HIGH);
  digitalWrite(PIN_ROW_5, LOW);
  curBuffer[16] = digitalRead(PIN_COL_1);
  //curBuffer[17] = digitalRead(PIN_COL_2);
  curBuffer[18] = digitalRead(PIN_COL_3);
  curBuffer[19] = digitalRead(PIN_COL_4);
  digitalWrite(PIN_ROW_5, HIGH);

  // 현재 스캔이 완료된 시간을 기록한다
  curMillis = millis();
  
  // 이전/현재 스캔 결과를 비교하여 모든 키를 처리한다
  for (int i = 0; i < MATRIX_SIZE; i++) {
    // 키입력 상태의 변화가 없을 때는 다음 키로 넘어간다
    if (prevBuffer[i] == curBuffer[i]) continue;

    // 너무 짧은 시간안에 상태가 변했다면 채터링으로 간주하고 무시한다
    if (curMillis - lastChange[i] < DEBOUNCE_DELAY) {
      curBuffer[i] = prevBuffer[i];
      continue;
    } else
      lastChange[i] = curMillis;
    
    // 문제가 없다면 해당 키의 마지막 상태변화 시간을 갱신한다
    lastChange[i] = curMillis;
    
    // 키를 변화방향을 확인하고 PC로 적절한 신호를 전송한다
    if (curBuffer[i] == 0)
      Keyboard.press(keycode[i]);
    else
      Keyboard.release(keycode[i]);
  }
  
  // 이전 스캔 결과와 현재 스캔 결과를 저장하는 배열을 서로 바꿔준다
  tempBuffer = prevBuffer;
  prevBuffer = curBuffer;
  curBuffer = tempBuffer;
}

 

9. 마치며

이것으로 커스텀 키보드 제작과정에 대해서 간단하게 알아보았습니다. 복잡한 기능이 들어간 키보드도 전체적인 흐름은 변하지 않으니 이정도만 기억하시면 충분히 만들 수 있을 거라고 생각합니다. 다음 글부터는 직접 키보드 제작에 들어가면서 보다 자세한 내용을 담을 예정입니다. 그럼 다음 글에서 뵙겠습니다.

제가 지금 사용하고 있는 키보드는 구매한 지 10년이 넘은 아이락스 펜타그래프 키보드입니다. 무선 레이저 마우스랑 세트로 된 콤보 제품인데, 1~2년 정도 사용하니 마우스가 심하게 버벅거리거나 키 입력이 씹히거나 하는 등 상태가 나빠졌습니다. 그냥 버리려다가 혹시 고칠 수는 없나 하고 검색해보니, 수신기만 새 걸로 교체하면 된다고 제조사 홈페이지에서 수리부속으로 팔고 있길래 해서 냉큼 사서 바꿔주니 문제없이 작동해서 그대로 쭉 사용하고 있습니다. 마우스가 고장의 원인이었는지, 수신기를 교체하고 얼마 안 돼서 다시 상태가 나빠지다 아예 먹통이 돼버렸습니다. 그대로 마우스는 버리고 키보드는 지금까지 계속 사용하고 있습니다.

 

사진 1. i-rocks의 RF-6570

여하튼 어찌어찌 10년 넘은 키보드를 사용 중인데 세월의 힘은 어쩔 수 없는지 우유처럼 하얗던 키보드가 발효돼서 치즈처럼 노랗게 돼버렸습니다. 변한 건 색뿐만은 아닌지 기름 빠진 고기처럼 푸석푸석해지고 탄력도 거의 없어졌습니다. 더러워져서 씻어주려고 키캡을 분리할 때 전에는 조금 억지로 분리해도 살짝 휘었다가 탄력 있게 원래대로 돌아갔지만, 이제는 정확하게 분해하지 않으면 그냥 부러져 버립니다. 고정하는 부분이 부러진 키들은 잘 안 쓰는 키랑 바꾸거나 했지만 이제는 슬슬 돌려 막을 키들도 없어져 가네요. 그래서 그냥 새 키보드를 장만하기로 했습니다.

 

사진 2. Micronics의 Manic Ex89

새 걸 사기로 하고 이것저것 알아보기로 한 것 까지는 좋은데, 예뻐서 혹하는 물건은 많았지만 마음에 쏙 드는 제품은 없었습니다. 우선 예전부터 모니터 중심과 키보드 중심이 일치하지 않아서 상체가 비틀리는 것이 조금 불만이었는데, 그걸 해결하기 위해 나온 텐키리스 제품 중에서 찾아보기로 했습니다. 기왕이면 제가 숫자 입력에 키패드를 자주 사용하기 때문에 내비게이션 키 대신에 키패드가 있으면 좋겠다고 생각하고 찾아보니 MANIC EX89 라는 제품이 딱 하나 나오네요. 하지만 각인이... 각인이 너무... 장난감 같아... 이건 좀 아니다 싶어 조금 더 찾아보기로 합니다. 게다가 기왕이면 방향키랑 키패드를 왼쪽에 배치하면 좋을 텐데 하고 찾아보니 해외에 판매 중인 제품이 조금 나옵니다만... 키패드가 왼쪽에 있으면 0 키는 오른쪽에 붙여줘야 하는 거 아닌가? 하는 생각이 들어서 잠시 보류. 결국 이것도 저것도 뭔가 조금씩 아쉬워서 차라리 그냥 직접 만들 수는 없나? 하고 찾아보니 예상외로 많은 자료가 나옵니다.

 

사진 3. Arduino Micro

생각보다 만들기가 어렵지 않은지 국내 여러 커뮤니티에서 키보드를 직접 만드신 분들을 찾을 수 있었고, 간단하게 아두이노를 사용해서 만드는 것부터 기판을 직접 설계하고 소자를 구매해서 만드는 자료도 있었습니다. 기판을 직접 만들면 스위치를 쉽게 교체하거나 LED를 달아서 각종 효과를 주는 등의 작업을 할 수 있지만 제작하기에 앞서 많은 공부가 필요합니다. 아두이노로 키보드를 만들어도 평범한 키보드 이상으로 많은 기능을 구현할 수 있고, 학교에서 배우는 납땜과 수학/과학 수준의 지식으로도 만들 수 있습니다. 아두이노를 사용하지 않더라도 프로그래밍을 통해 입/출력을 제어할 수 있는 MCU(Micro Controller Unit)가 달린 제품(라즈베리 파이, 라떼판다 등)이라면 키보드를 만들 수 있습니다. 하지만 크기와 가격, 제작 편의성 등을 생각해 Mega32u4 를 사용한 아두이노 마이크로나 그 호환보드를 활용해 키보드를 만들기로 했습니다.

 

사진 4. The Dactyl Keyboard

커스텀 키보드를 만든다는 것은 자신의 취향에 맞는 키보드를 만들기 위한 것이지만, 그 방향성은 크게 2가지 기능 중시형과 감각 중시형으로 나눌 수 있습니다. 기능 중시형은 저처럼 자신에게 맞는 키의 배열(레이아웃)이나 기능(레이어, 매크로), 입력방식(노브, 트랙볼, 휠, 아날로그 스틱, 터치패드) 등을 중심으로 키보드를 만듭니다.반면 감각 중시형은 타건감이나 타건음 등을 위해 키캡(프로파일), 스위치(윤활, 스프링 교체), 스테빌라이저, 하우징(보강판, 흡음재, 무게추) 등을 구성하고 조절합니다. 전자는 디자인(설계)에 후자는 튜닝(조율)에 가깝다고 할 수 있습니다. 커스텀 키보드(기계식 키보드)를 접하는 것은 이번이 처음이라 튜닝에 관한 이야기는 깊이 다루지 않겠습니다. 관련 지식이나 경험도 부족하니, 제작을 위해 수집한 자료를 간단하게 정리하는 수준으로만 다루고, 아두이노로 만드는 키보드라는 2가지 주제를 중심으로 제작기를 써보려고 합니다.

 


참고링크

키보드 매트릭스 : http://www.kbdmania.net/xe/tipandtech/8794285

키보드 제작기 : https://gall.dcinside.com/mgallery/board/view?id=mechanicalkeyboard&no=830197

커스텀 디자인 : http://xahlee.info/kbd/diy_keyboards_index.html

+ Recent posts