자바스크립트를 활성화 해주세요

모스(Morse) 부호 키보드 만들기

 ·   ·  ☕ 11 min read  ·  ✍️ Yogo

잠이오지 않아 뒤척이던 어느 늦은밤 커뮤니티의 게시물을 훑어보던 도중 재미있는 짤을 하나 발견했습니다.

onekeyboard

아앗!

작고 아름다운 그것은 야심한 새벽에 그렇게 제 마음에 들어왔습니다.

마침 잠도 오질 않았기에 모스 키보드를 만들기 위해 필요한 정보와 부품들을 탐색하게 되었습니다.

모스 부호의 기본

모스 코드에 대해서 대충 짧고 긴 신호로 메시지를 전한다는 것만 알고 있었지 자세히 아는 것은 없었습니다. 그래서 간단하게 체계를 우선 파악하기로 했습니다.

모스 코드는 크게 dot(또는 dit), dash(또는 dah)로 신호 접점을 누르는 시간에 따라 신호 구분을 하고 이 신호의 조합에 따라 정해진 글자(character)를 전달하도록 되어있습니다. 참고로 신호 길이의 비율은 dot이 1이라고 하면 dash는 3이고, 신호 간격 1, 글자(word) 간격은 3이라고 합니다.

만약 ㆍㅡ 와 같이 두 신호를 입력하게 되면 알파벳으로는 ‘A’자가 되며, 이러한 부호 조합은 아래의 표와 같습니다.12

한글 알파벳 모스부호 숫자,특수문자 모스부호
L ㆍㅡㆍㆍ 1 ㆍㅡㅡㅡㅡ
F ㆍㆍㅡㆍ 2 ㆍㆍㅡㅡㅡ
B ㅡㆍㆍㆍ 3 ㆍㆍㆍㅡㅡ
V ㆍㆍㆍㅡ 4 ㆍㆍㆍㆍㅡ
M ㅡㅡ 5 ㆍㆍㆍㆍㆍ
W ㆍㅡㅡ 6 ㅡㆍㆍㆍㆍ
G ㅡㅡㆍ 7 ㅡㅡㆍㆍㆍ
K ㅡㆍㅡ 8 ㅡㅡㅡㆍㆍ
P ㆍㅡㅡㆍ 9 ㅡㅡㅡㅡㆍ
C ㅡㆍㅡㆍ 0 ㅡㅡㅡㅡㅡ
X ㅡㆍㆍㅡ . ㆍㅡㆍㅡㆍㅡ
Z ㅡㅡㆍㆍ , ㅡㅡㆍㆍㅡㅡ
O ㅡㅡㅡ ? ㆍㆍㅡㅡㆍㆍ
J ㆍㅡㅡㅡ / ㆍㅡㅡㆍㅡ
E : ㅡㅡㅡㆍㆍㆍ
I ㆍㆍ ; ㅡㆍㅡㆍㅡㆍ
T ' ㆍㅡㅡㅡㅡㅡㆍ
S ㆍㆍㆍ " ㆍㅡㆍㆍㅡㆍ
A ㆍㅡ ( ㅡㆍㅡㅡㆍ
N ㅡㆍ ) ㅡㆍㅡㅡㆍㅡ
H ㆍㆍㆍㆍㆍ - ㅡㆍㆍㆍㅡ
R ㆍㅡㆍ $ ㆍㆍㆍㅡㆍㆍㅡ
D ㅡㆍㆍ _ ㆍㆍㅡㅡㆍㅡ
U ㆍㆍㅡ 정정부호
Y ㅡㆍㅡㅡ 한글 ㆍㆍㆍㅡㆍ
Q ㅡㅡㆍㅡ 영문 ㆍㆍㆍㆍㆍㆍㆍㆍ

기존 제품 분석 및 설계

기존 제품 분석

짧은 영상이라 분석이라고 할 것 까지는 없지만 영상을 보면 몇가지 특징을 확인 할 수 있었습니다.

  • 모스 신호 입력을 위해서 단 하나의 키 입력만 사용
  • 신호 입력 과정을 눈으로 확인하기 위해서 Dot과 Dash 정보도 전송(타이핑)
    • 변환된 문자가 입력되기 전에는 입력된 Dot과 Dash는 지움
  • 모스 코드로는 입력 불가한 코드 입력을 위해 별도의 커스텀 코드를 사용하는 것으로 추정
  • 대문자 입력을 위해서 Shift가 눌린 것처럼 하기 위해서 커스텀 코드를 사용하는 것으로 추정
    • H 입력 후에 소문자 e 입력 하기전에 신호 입력 과정이 ‘.‘이 ‘>‘로 ‘-’, ‘_‘로 변한 것을 볼때 유추

위에 나열된 특징을 요약하자면 모스코드 신호 입력 과정이 표시되며, 커스텀 코드를 사용하여 기존 모스코드에 없는 문자 입력이나 대/소문자 입력을 하는 것으로 보였습니다.

관련 정보를 찾아보던 도중 영상의 키보드는 모스 키 입력을 위해서 만들어진게 아니라 단일 키 입력이 가능한 키보드일지도 모른다는 생각이 들었습니다. 유사한 제품이 판매하는 것을 보았기 떄문입니다.

그래서 모스 신호 입력 및 변환은 아마도 입력된 키 값 또는 별도의 프로그래밍으로 변환하는 과정을 거친게 아닐까 예상이 되기도 합니다.

기능 설계

위에 간단하게 분석된 내용을 바탕으로 단순히 그대로 구현하는 것보다는 독자적인 기능이나 편의사항 등을 고려하여 몇가지 개선점과 추가 기능을 고려해보았습니다. 그리고 별로의 프로그램을 사용하지 않는 단독으로 입력과 변환이 가능하도록 설계를 하기로 했습니다.

  • 한글 입력을 고려
    • 자/모 분리가 되는 현상을 회피하기 위해서 신호 입력과정 표시 유무 선택 가능
    • 신호 입력 과정(dot, dash)을 디바이스 자체에서 LED 또는 LCD로 시각적 표시 고려
  • 대소문자 입력은 Shift 키가 아닌 Caps Lock 키 입력을 통한 대소문자 변환 고려
    • 신호 입력 과정이 점과 대시가 아닌 괄호와 언더바로 표시되는 현상을 개선
  • 띄어쓰기나 들여쓰기 등 지원하지 않는 입력이 가능하도록 부가적인 커스텀 코드 적용
  • 키 입력 시 부저(buzzer)를 이용하여 모스 신호 소리와 유사한 효과 선택 가능
  • Dot, Dash 입력 타이밍을 사용자가 임의로 설정 또는 입력 타미잉을 보정 하는 기능 고려

모스 코드 신호를 분석해서 키보드 입력으로 전송하는 기본적인 기능 이외에 시각적, 편의적 기능을 추가적으로 고려하였습니다.

기능이 추가로 인해 하드웨어/소프트웨어 복잡성 증가로 회로도 커지고 고려사항이 많아지겠지만, 보통 개인 프로젝트를 할 때에는 어떤 것을 만들었다라는 결과적 성취감 보다는 만들면서 새로운 것을 배우고 고민하고 해결하는 과정을 좋아하기 때문에 가급적 신규 기능을 최대한 수용하기로 했습니다.

하드웨어(Hardware) 설계 및 작성

MCU 선정

영상처럼 컴팩트한 느낌으로 만들려면 PCB를 설계부터 적정한 케이스를 찾거나 또는 만들어야겠지만 시간, 비용을 고려할 때 일회성 프로젝트데 많은 것을 투자할 수는 없어서 작업 용이성과 완성도 사이이의 적정한 타협이 필요했습니다.

그래서 다음과 같은 몇가지 조건을 정했습니다.

  • 완성된 디바이스 사이즈는 50 x 50mm 이하를 목표
  • 20 ~ 30핀 이하의 소형 MCU(Micro Controller Unit) 디바이스 사용
  • 편의성을 위하여 미리 만들어진 하드웨어 플랫폼(아두이노, 라즈베리파이 제로 등) 사용 배제
  • 만능기판 작업을 고려하여 DIP 타입 패키지가 제공되어야 할 것

미디어 제어용 디바이스 구상을 하면서 필요한 MCU 디바이스를 찾아보고 있었기 때문에, 이후 프로젝트도 고려하여 개발이 용이한 MCU를 선정하기로 했습니다. 우선 대상은 STMicroelectronics(이하 STM)사의 STM32 시리즈 또는 Microchip사의 PIC8, 16, 32 시리즈를 우선하기로 했습니다.

처음에는 단순한 기능 요구사항만 소형 사이즈의 8bit 프로세서를 적극 고려하였으나 처리 성능이나 peripheral 세부 기능 차이에서 부터 개발 플랫폼까지 32bit 프로세서 대비 상대적으로 부족하거나 펌웨어 개발 시 고려사항이 늘어날 것으로 판단이 되었고, 잠깐 블루투스를 고민하여 nordic사의 nRF 시리즈도 찾아보았지만 이 경우는 하드웨어 고려사항이 너무 많아지므로 나중을 기약하고 USB peripheral을 제공하는 32bit 프로세서를 사용하는 것으로 결정했습니다.

결국 STM32와 PIC32 중에서 선택을 해야 했는데 마이크로칩 같은 경우에는 다른 제조사와 달리 거의 유일하게 DIP 타입 패키지를 제공하기 때문에 결론은 요구사항에 가장 부합하는 마이크로칩 사의 PIC32MX230F256B 28핀 디바이스로 결정하였습니다.

기타 하드웨어

프로세서 외의 부품 중에서는 키보드 부품이 중요했는데 요즘은 기계식 키보드 축을 따로 팔고 있으므로 게이트론 저소음 갈축이 8개 세트로 판매가 되고 있길래 해당 축을 선택하였고, 그 외 회로 구성을 위한 기판, 스위치, RLC, LED 와 같은 부품을 선정하여 리스트 업 했습니다.

회로 구성 및 작성

회로도는 현재 Autodesk에 인수된 Eagle CAD를 사용하였습니다. 인수되어 구독형 제품으로 제공되고 있는데 무료버젼도 제공하고 있고, 해당 버젼만으로도 충분하기 때문에 수월하게 회로도 작성이 가능했습니다.

schematic

펌웨어(Firmware) 설계 및 작성

대학생때 USB 2.0 공부해보겠다고 스펙시트 500페이지 넘는걸 전체 인쇄해서 보고, 구하기도 힘든 칩은 해외 제조사에 샘플 신청해서 받아본 기억이 납니다. 다시 보려니 엄두는 안나지만 요즘은 제조사에서 친절하게 프로토콜 스택과 간단한 예제를 제공해주니 그걸 바탕으로 우선 키보드로서 동작이 되도록 하였습니다.

개발환경

typing
harmony

마이크로칩의 경우에는 MPLAB X라는 NetBeans IDE 기반(참고로 STM사 IDE는 Eclipse 기반)를 개발환경을 제공합니다. 32bit 프로세서가 출시된 이후부터는 이전에 Pheriperal, 통신 프로토콜(USB, Ethernet) 또는 특정 애플리케이션(LCD, Codec 등) 개별로 전용 라이브러리만 제공하던 것 대신 Harmony라는 이름으로 통합 소프트웨어 스택을 제공합니다. 그리고 별도의 내장 유틸리티로 기존 데이터 시트를 참고하여 일일히 작성하던 코드 대부분을 GUI로 쉽게 지정 및 생성할 수 있도록 변경되었습니다.(STM사 CubeMX와 유사)

그럼 디테일한 설명은 지면상 생략하고 디버깅을 위한 UART와 USB 스택, 기타 필요한 것들을 배치하여 베이스 코드가 생성되도록 합니다.

별도로 ThreadX나 FreeRTOS 등을 추가로 선택할 수도 있지만 굳이 RTOS까지 사용할 필요는 없으니 RTOS는 제외합니다.

핀설정와 클럭 설정까지 완료하여 Harmony기반 베이스 코드를 생성하는 경우 Non-OS 환경이라도 명목상 Task라는 이름과 State 및 Callback 기반 펌웨어를 작성할 수 있는 기반을 마련해줍니다.

그리고 장치나 소스코드에 따라 App_Task 와 같이 [코드 또는 장치 이름]_[함수명] 같은 구조로 생성이 됩니다. 개인적으로 C 개발 한정 snake case (소문자 및 언더스코어) 방식으로 프로그래밍을 하는데 일관성 유지를 위해서 최대한 자동 생성된 코드와 코드 컨벤션을 일치 하도록 합니다.

모스 부호 인식

모스 부호는 짧은 신호와 긴 신호 두가지로 구분이 됩니다. 스위치를 누르는 시간을 측정하면 되므로 인풋캡쳐(Input Capture) 장치(peripheral)를 사용하여 신호 변화에 따른 시간 길이를 측정하거나 포트 인터럽트(Port Interrupt)와 타이머(Timer)를 사용해서 시간을 측정하는 방법이 있습니다. 여기서는 후자의 방법을 사용하였고 간단하게 1ms로 타이머 인터럽트 시 시간 카운트를 하도록하고 포트 신호가 변경 될 때 카운터를 리셋하거나 카운트를 세서 시간을 측정하는 단순한 방식을 사용했습니다.

이렇게 측정된 시간에 따라서 dot, dash를 구분하고 신호를 누적하여 임시 저장합니다. 대략 이 시간은 dot은 150 ms, dash는 dot의 3배수를 두고 약간의 tolerance 시간을 두고 기준 시간 입력을 초과하였는지 여부로 간단하게 dot과 dash를 구분하게 하였습니다. 그리고 일정 시간이상 입력이 없거나(timeout)가 지정한 시간에 미치지 못하게 되면 입력이 완료된 것으로 간주하고 누적된 신호를 문자로 변환하는 과정으로 넘어가게 됩니다.

모스 부호 변환

모스 신호는 두가지 상태만 존재하며, 모스 코드 테이블을 보면 신호의 길이는 최대 8을 넘지 않는 것을 확인 할 수 있습니다. 이러한 특징으로 신호는 두가지 밖에 없으므로 이진수(binary)로 표현 할 수 있고(dot: 0, dash: 1), 길이는 최대 8을 넘지 않으니 char 타입(1바이트)이면 입력된 신호를 임시로 저장하고 변환하는데 충분할 것으로 예상 할 수 있습니다.

그래서 신호를 이진화하여 좌측으로 쉬프트 하면서 채워 나가면 입력된 신호를 1바이트 값에 저장할 수 있습니다. 다만 이경우 ㆍ 이나 ㆍㆍ 처럼 char 기준 모두 0으로 동일한 값이 되는 문제가 있습니다. 하지만 신호 길이가 다르므로 신호를 누적하여 저장함과 동시에 입력된 신호 길이를 재서 변환 시 참고를 하면 각자 다른 부호로 인식할 수 있습니다.

1
2
3
4
5
6
7
unsigned char buffer = 0;
unsigned char length = 0;

void input_signal (char signal) {  
  buffer = (buffer << 1) | signal;  // signal is 0 or 1
  length += 1;
};

그럼 입력 가능한 모든 모스 신호를 문자로 변환하기 위해서 미리 변환하여 룩업(Lookup) 테이블을 작성합니다.

1
2
3
4
5
6
7
unsigned char code_table[][2] = {
  ...
  { 0x01, 1 },  // A
  { 0x08, 4 },  // B
  ...
};

이렇게 작성된 테이블은 신호 입력이 완료되면 신호 길이와 코드 값으로 테이블 인덱스(index) 찾아서 해당 값을 바탕으로 HID(Human Interface Device) 키보드 코드로 변환을 해서 호스트 기기(PC)에 전송을 하면됩니다.

저의 경우는 HID 키보드 코드 변환전에 개발의 용이와 유지보수를 위해서 제가 읽기 쉽도록 ASCII 코드로 변환 과정을 한번 더 거치도록 하였습니다.

그래서 모스코드 테이블의 항목들은 아스키코드 순서대로 배치를 하도록 하였고, 모스부호에서 지원하지 않는 코드들은 일부 커스텀 코드로 대체하거나 또는 오프셋(offset) 유지를 위해서 빈 값(코드, 길이 모두 0)을 채우도록 하였습니다.

그래서 전체적인 모스 신호 변환 시퀀스를 나열하면 아래와 같은 순서로 진행됩니다.

키 입력(짧음, 김) -> 2진화 -> 바이트 변환 및 길이 저장 -> ASCII 코드 변환 -> HID 키보드 값 변환

참고로 $와 숫자 4는 같은 HID 키보드 코드를 사용합니다. 그래서 $나 괄호같은 값은 쉬프트가 필요하므로 HID 키보드 코드와 함께 modifier(컨트롤, 쉬프트, 알트 등) 정보를 같이 전송하게 합니다.

기타 기능

키입력을 이진화 하는 과정을 타이핑으로 보여주기 위해서서는 .(dot)과 -(dash) HID 키보드 코드를 전송합니다. 이 기능은 DIP 스위치로 끄고 켤 수 있도록 합니다. 대신 이 기능이 활성화 되어 있을 경우에는 입력된 dot과 dash를 모두 지워준 뒤에 입력될 키를 전송해야합니다. 그리고 dot과 dash가 입력되는 상황을 보여주기 위해서 키보드에 red, green 두가지 색 표시가 가능한 LED를 달아서 dot이 입력되면 빨간색, dash가 입력되면 green 표시를 해줍니다. 이 또한 DIP 스위치로 끄고 켤 수 있도록 합니다. 마지막으로 키가 눌릴때마다 MCU의 OC(Output Capture)를 이용해서 대략 800hz의 PWM(Pulse Width Modulation)로 제어하여 부저에서 신호 소리가 나올 수 있도록 하였습니다. 그리고 이 기능또한 DIP 스위치로 끄고 켤 수 있습니다.

미완 기능

dot, dash 인식을 위한 시간 값을 사용자 임의로 지정하기 위해서 각각 신호의 길이를 5개씩 측정해서 평균값을 사용하는 기능을 기획했으나 일단 초기 릴리즈에서 제외하였습니다.

테스트 및 제작

실제 회로를 제작하기에 앞서 기능 테스트를 위해서 오래전에 구입하고 방치해두었던 디바이스를 브레드보드에 장착시켜서 펌웨어 테스트만 진행하였습니다.

test

펌웨어 기능을 확인 후 부품을 준비해서 땜질을 해봅니다.

parts

parts

완성 및 시연

간만에 뜨개질 좀 했습니다.

demo
유튜브: https://youtu.be/risKpr9GJgU
모스부호에 익숙치 않아서 천천히 눌러서 촬영을 하였는데, 공유된 영상은 실제보다 2배 빠른 속도입니다.

완성된 디바이스의 회로도와 펌웨어는 Github에 공개 하였습니다.
https://github.com/micro-artwork/simple_morse_keyboard