중급 예제

약간은 익숙하시거나 익숙해지셨나요? 그렇다면 조금더 깊이 다뤄볼까요?

모스 부호 번역기

2014-08-06 09:44:16

개요

시리얼모니터에 문자나 숫자를 입력하면 이를 LED의 깜빡임으로 모스부호로 표현하는 회로를 구현해보자.

해군에서는 아래사진과 같이 아직도 해상에서 다른배와 송수신을 할때 조타병이나 부사관이
직접 모스부호를 외워 손으로 기기를 움직여 모스부호를 표현한다. 




전통일 수도 있겠지만 이런곳에 아두이노로 만든 모스부호 번역기가 쓰이게 된다면 유용하지 않을까 생각해 본다.

이번에 만드는 모스부호 번역기는 전 튜토리얼인 SOS만들기의 회로와 부품을 똑같이 사용하되 소스만 변형하면 만들 수 있다.
LED부분을 좀 더 화려하게 꾸미면 좀 더 멋진 작품을 만들 수 있을 것이다. 


 

동영상

 

 

※모스부호표


 

 

부품 목록

NO 부 품 명 수 량 상 세 정 보
1 아두이노 1  오렌지 보드
2 브레드 보드 1  
3 red LED 1  
4 270Ω저항 1  
5 케이블 2  

 

 

 

부품명 아두이노 브레드 보드 red LED 270Ω저항 케이블
부품 사진

 

 

 

하드웨어 making

전자 회로도


 

 

회로도

 

 

 

 

 

 

 

소프트웨어 coding

/*
33가지 프로젝트로 배우는 아두이노
 - 모스 부호 번역기
*/

int ledPin = 12; char* letters[] = {".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", ".." , // A-I 
                                    ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", // J-R 
                                    "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--.." }; // S-Z 
char* numbers[] = {"-----", ".----", "..---", "...--", "....-", ".....", // 0-9 
                   "-....", "--...", "---..", "----." }; 
int dotDelay = 200; 
void setup() { 
  pinMode(ledPin, OUTPUT); //12번 LED핀을 OUTPUT모드로 선언 
  Serial.begin(9600); //시리얼통신 속도 설정 
} 
void loop() { 
  char ch; 
  if(Serial.available()) { //시리얼 포트에 데이터가 전송되어 있을때 
    ch = Serial.read(); //데이터를 읽어서 ch변수에 저장한다 
    Serial.print(ch); 
    Serial.println(" -> Convert morse code"); //각각 문자의 경우에 맞게 flashSequence함수 호출 
    if(ch >='a' && ch <= 'z') { //소문자 
      flashSequence(letters[ch-'a']); 
      Serial.println(letters[ch-'a']); 
    } 
    else if(ch >='A' && ch <= 'Z') { //대문자 
      flashSequence(letters[ch-'A']); 
      Serial.println(letters[ch-'A']); 
    } 
    else if(ch >='0' && ch <= '9') { //숫자 
      flashSequence(numbers[ch-'0']); 
      Serial.println(numbers[ch-'0']); 
    } 
    else if(ch <= ' ') //빈공간 
      delay(dotDelay*4); 
  }
} 
//각 문자에 맞는 모스부호의 기호를 쪼개어서 flahDotOrDash함수의 인자값으로 지정한다. 

void flashSequence(char* sequence) { 
  int i = 0; 
  while(sequence[i] != NULL) { 
    flashDotOrDash(sequence[i]); //쪼갠 문자들을 flashDotOrDash()안의 인자값으로 넣는다 
    i++; 
  } 
  delay(dotDelay*3); 
}
//모스부호의 장,단 길이에 맞춰서  LED를 깜빡인다
void flashDotOrDash(char dotOrDash) {
  digitalWrite(ledPin, HIGH);
  if(dotOrDash == '.') //점일 경우 짧게 깜빡임
    delay(dotDelay);
  else
    delay(dotDelay*3); //점이 아닌 선일 경우 길게 깜빡임
  
  digitalWrite(ledPin, LOW);
  delay(dotDelay);
}


소스가 복잡한데 소스를 분할해서 분석한다면 생각보다 쉽게 알아차릴 수 있다.
letters[]배열은 각 문자의 모스부호 기호를 순서대로 저장한 배열이고 numbers[]배열은 0부터 9까지의 모스부호를 순서대로 저장한 배열이다.

 

void setup() {                
  pinMode(ledPin, OUTPUT); //12번 LED핀을 OUTPUT모드로 선언
  Serial.begin(9600);  //시리얼통신 속도 설정
}

setup에서는 12번핀을 OUTPUT으로 설정하고 시리얼통신을 위한 속도를 9600으로 설정한다.

 

 

 

//각각 문자의 경우에 맞게 flashSequence함수 호출
    if(ch >='a' && ch <= 'z') {  //소문자
      flashSequence(letters[ch-'a']); 
      Serial.println(letters[ch-'a']);
    }
      
    else if(ch >='A' && ch <= 'Z') {  //대문자
      flashSequence(letters[ch-'A']);
      Serial.println(letters[ch-'A']);
    }
      
    else if(ch >='0' && ch <= '9') {  //숫자
      flashSequence(numbers[ch-'0']);
      Serial.println(numbers[ch-'0']);
    }
      
    else if(ch <= ' ')  //빈공간
      delay(dotDelay*4); 

loop안의 if문에서는 입력받은 문자에 따라 분류하는데 소문자, 대문자, 숫자, 공백으로 분리하였다. 
만약 소문자를 입력받게 되면 'a'를 빼게 되는데 이는 아스키코드를 이용한 것으로 만약 문자 a를 입력받았을 경우 a의 아스키코드값은 97이 되는데 a-a = 0이 되어 letters[0], 곧 a에 해당하는 모스부호를 불러와서 flashSequence함수의 매개변수로 넣어주게 된다.

다른 예를 다시 들면 대문자 G를 입력 받았을 경우 대문자 G는 아스키코드 십진법으로 71에 해당한다. 대문자 A는 아스키코드 십진법으로 65에 해당하고 G-A = 6이라는 결과가 나오게 된다. letters[6]은 G의 모스부호가 저장된 배열이므로 정확하게 입력받은 문자의 해당하는 모스부호를 배열에서 구할 수 있게 된다. 공백일 경우에는 delay를 200*4 = 0.8sec의 delay를 주게 된다.

 

 

 

 

//각 문자에 맞는 모스부호의 기호를 쪼개어서 flahDotOrDash함수의 인자값으로 지정한다.
void flashSequence(char* sequence) {
  int i = 0;
  while(sequence[i] != NULL) {
    flashDotOrDash(sequence[i]); //쪼갠 문자들을 flashDotOrDash()안의 인자값으로 넣는다
    i++;
  }
  delay(dotDelay*3);
}

flashSequence함수에서는 loop에서 분류된 입력문자의 모스부호를 변수로 받게 되는데, while문을 통해 문자의 해당하는 모스부호를 장,단 기호로 짧게 분리한다.
예를들면 문자 B에 해당하는 모스부호는 -... 이고 이 모스부호를 flashSequence에서 변수로 받게되면 sequence에는 -...가 저장된다.
sequence배열 순서대로 sequence[0] = "-", sequence[1] = ".", sequence[2] = ".", sequence[3] = "."이 저장되고 while문을 통해 각각의 배열의 문자들은 flashDotOrDash함수로 넘어가게 된다. while문의 조건은 sequence배열에 값이 존재하지 않을때까지 반복하게 된다.

 

 

 

 

//모스부호의 장,단 길이에 맞춰서  LED를 깜빡인다
void flashDotOrDash(char dotOrDash) {
  digitalWrite(ledPin, HIGH);
  if(dotOrDash == '.') //점일 경우 짧게 깜빡임
    delay(dotDelay);
  else
    delay(dotDelay*3); //점이 아닌 선일 경우 길게 깜빡임
  
  digitalWrite(ledPin, LOW);
  delay(dotDelay);
}

flashDotOrDash함수에서는 이제 잘개쪼개진 기호에 맞게 단이면 digitalWrite의 HIGH와 LOW사이의 delay를 짧게 주어 짧게 깜빡임을 나타내고, 장이면 digitalWrite의 HIGH와 LOW사이의 delay를 길게 주어 길게 깜빡이게 한다. 각각의 delay는 단기호 일때는 0.2sec의 delay를 주고 장기호일때는 0.6sec의 delay를 주어 표현한다.


위와같이 loop에서는 문자를 모스부호로 변환, flashSequence()에서는 모스부호를 장단기호로 더 짧게 분할, flashDotOrDash()함수에서는 짧게 분할된 기호에 맞게 LED의 깜빡임을 표현
이런 방법으로 소스를 구현하여 입력받은 모스부호를 나타내었다. 소스내에 char타입 변수의 연산을 통해 암묵적인 아스키코드의 사용도 존재하고, 설명하지 않은 포인터기호도 들어가 어렵지만 이해한다면 마냥 어렵지만은 않은 소스일것이다.

 

 


 

kocoafabeditor

항상 진취적이고, 새로운 것을 추구하는 코코아팹 에디터입니다!

LED, 아두이노, 오렌지보드

chobo 2019-05-20 00:36:48

220v 전구에 연결할려면 릴레이를 써야할텐데요. 그러면 저항은 필요없나요?