반응형

【 아두이노모듈#31】 #1. 활용성 좋은 HC12 무선 모듈, 봉지 뜯은 김에 마스터해보기 


※ 모든 이미지는 클릭 시 확대되어 선명하게 보실 수 있습니다.


【 HC12 무선 개요 】

 ( Long Range RF Wireless Serial Module ) 
 HC-12 무선 모듈은 433MHz 대역을 사용하는 양방향 통신 무선 모듈이며,  1 대 1 (1 : 1) 통신뿐 아니라,  1 대 다(1 : N) 멀티채널 통신이 가능한 모듈입니다.  통신을 위해서는 최소한 2개의 모듈이 필요합니다. 
 통신주파수가 더 높은 고주파 대역을 사용하는 (예, 2.4 GHz) 무선기기들 보다 장애물에 좀 더 유연하며,  MCU를 내장하고 있어 직렬 포트를 통한 외부 장치와의 통신도 가능한 장점이 있습니다.
  전원을 넣으면 바로 연결이 되고, 응답성이 좋아, 다양한 사물기기간의 통신뿐 아니라,  무선조정 RC-Car와 같은 작품들을 만드는 데에도 활용하기 좋은 모듈입니다.  

 

〔 주요 특징 〕
- 장거리 무선 전송 ( 열린 공간에서 1,000 m의 거리를 5000 bps의 속도로 신호 전송 가능 , 저속 모드 시 1.8Km까지도 가능 )
- 모듈에 MCU가 내장되어 있어 모듈에 별도의 프로그래밍을 해줄 필요 없이 시리얼포트를 통한 AT 명령으로 전송 모드를 선택하거나 설정을 제어할 수 있습니다. 
- 절전모드(FU1), 초절전모드(FU2), 일반모드(FU3), 원거리통신모드(FU4) 등의 다양한 옵션을 제공해 줍니다.
- 100개의 채널을 활용할 수 있습니다. (작동 주파수 범위 : 433.4MHz ~ 473.0MHz , 400KHz 간격으로 100개)
- 시리얼(직렬) 포트를 통한 외부 장치와의 통신이 가능합니다.

〔 주요 사양 〕
- 작동 주파수 :  433.4MHz ~ 473.0MHz , 400KHz 간격으로 100개의 채널 사용가능
- 공급 전압    :  3.2V~5.5V
- 통신 거리    :  열린공간에서 1,000m  ,   저속모드 선택 시 1.8Km 가능,  외부 확장 안테나 연결단자 있음
- 시리얼 통신 속도 : 1200 bps / 2400 bps / 4800 bps / 9600 bps (default) / 19200 bps / 38400 bps / 57600 bps / 115200 bps
- 수신 감도    : -117dBm ~ -100dBm
- 전송 파워    : -1dBm ~ 20dBm
- 인터페이스 프로토콜 : UART / TTL
- 작동 온도    : -40℃ ~ +85
- 크  기         : 27.8mm x 14.4mm x 4mm

▶ HC-12 확장 안테나
(송신 거리 혹은 수신 감도를 높이기 위해 필요에 따라 아래와 같은 확장 안테나를 연결할 수 있습니다.  하지만 반드시 필요한 것은 아니며,  대부분의 경우 기본에 포함된 스프링 안테나를 이용하여도 충분합니다. )

확장 안테나
확장 안테나 연결 부위 확대 모습
확장안테나를 연결한 모습 (nRF24L용 안테나와 호환 가능)
스프링 안테나의 연결(납땜) 위치
스프링 안테나와 확장안테나 위치 표시

아래는 스프링 안테나와 핀의 납땜 모습입니다.  스프링은 세우지 않고 일자로 눕혀 납땜해도 상관없고,  핀도 90도 직각으로 꺾이는 핀을 따로 구해서 HC-12 모듈이 기판이나 브레드보드에 세워 꽂을 수도 있으니 참고하세요.


HC12의 스펙을 하나의 테이블로 보기 좋게 정리해보았습니다

 

 HC12의 FUx 모드 설정에 대한 상세 설명 

 

 HC12의 AT Commands 명령어 정리 


[HC12 모듈 간 통신 방식 설명]


HC12 모듈은 아래 이미지처럼, PC(시리얼 모니터)와 시리얼 방식으로 통신을 합니다.


그리고 HC-12 모듈 사이에 433 MHz 대역으로 RF 무선통신을 하게 됩니다.

 

【 HC12 모듈 실습 - 전체 과정 안내 】

 :  HC12 모듈을 구매하셨다면, 봉지를 뜯은 김에(?) 기초 실습부터 단계별로 진행하여 어느 정도 HC12 모듈을 잘 다룰 수 있는 실습까지 이 번에 모두 담아 보려 했습니다.   최종적으로 서보모터 2개를 동시에 무선으로 제어 해보는 실습까지 진행해 본다면, DC모터를 제어하는 것은 좀 더 쉽기 때문에 RC-Car와 같은  RC 기기류는 자유롭게 만들 수 있게 됩니다.  차기 콘텐츠에는 HC12모듈 활용 편으로 RC-Car를 진행할 예정이니 관심 있으신 분들은 이번 실습을 차근차근 진행해보면 많은 도움이 될 것으로 기대합니다.

《 실습 진행 순서 》
실습 #1에서는 HC12 모듈의 시리얼 통신 기능을 배워볼 텐데요, PC ↔ HC12를 시리얼 모니터를 이용한 시리얼 통신기능 학습입니다.

실습 #2에서는 HC12 모듈 간의 RF 통신 실습입니다. 회로를 1대 1,  또는 1대 2이상 구성한 다음, 시리얼 통신 기능을 이용해서 RF를 통해 문자를 주고받고, 받은 문자에 따라 LED를 켜보는 실습입니다. 

실습 #3은 AT-Command 통신 기능을 사용해보는 실습입니다. AT-명령어를 시리얼 모니터 창으로 입력하여 HC-12 모듈의 채널(주파수) 변경/전송 모드 변경/통신속도/통신 강도 변경 등을 실습합니다.

실습 #4에서는 RF 통신을 이용하여 AT-Command 기능을 활용해 보는 실습입니다.  푸시버튼스위치 2개를 이용하여, 무선통신으로 원격으로 HC12 모듈의 채널을 바꾸어 보는 실습입니다.  이번 실습 4를 이용하면, 채널(주파수) 변경뿐 아니라, 실습 3에서 해보았던, 전송 모드 변경/통신속도/통신 강도 변경 등도 할 수 있습니다. 

실습 #5가변저항을 돌려서 RF 통신으로 원격 회로의 LED 밝기를 조절해 보는 실습입니다. 이번 실습을 통해, 기본적인 데이터 주고받는 방법과 입·출력 포트 제어를 이해할 수 있습니다.

실습 #6은 조이스틱 모듈 하나로 원격의 서보모터 두 대를 제어해 보는 실습입니다.  보통 실습 2에서 처럼 무선으로 수신되는 데이터가 한 가지라면, 처리하기 쉽지만,  조이스틱 모듈에서 나오는 두 가지 데이터를 수신받아, 두 개의 서보모터(x, y) 데이터로 각각 분리하여 다루는 코딩 방법을 익히게 됩니다.  서보 모터를 다룰 수 있게 되면, DC 모터는 더 편하게 다룰 수 있습니다.

 앞 단계 실습이 쉬워 보이더라도, 가급적 순서대로 모든 실습을 직접 해보시길 추천드립니다. 
실습에 사용된 아두이노는 사이즈가 작고 별도의 USB to TTL 모듈이 필요치 않은 나노(Nano) 보드를 이용했습니다.
만약, 나노가 아닌 다른 보드를 사용하여도 되며,  특히 우노(Uno) 보드를 사용한다면, 회로의 연결이나 코딩의 변경 없이 거의 그대로 사용할 수 있습니다.


《 실습 재료 》

본 게시글의 모든 이미지는 클릭하면 선명하게 확대 됩니다

위의 실습재료는 실습 1~실습 6까지 전체 실습을 진행할 수 있는 최소한의 재료입니다. 
만약 실습 2에서와 같은 여러 대의 통신 실습을 진행하려면, ~개 이상이라고 표시된 부품들이 더 필요할 수 있으니 참고하세요.  기본적으로, 아두이노 나노(우노) 2대와 HC12 2개의 송수신 회로를 가지고, 연결을 바꾸어가며, 실습 1부터 실습 6까지 진행하실 수 있습니다.

【 실습  #1 】 나노 HC12회로 두 대를 이용한 시리얼 통신 실습

아래 회로 연결도를 구성해 주고 PC와 연결합니다.
▶ 회로 연결도 
(아두이노 나노와 RF 무선통신 모듈 HC12 연결도)
    ※ 아래와 같은 회로 두 개를 준비합니다.

 

《 콘덴서를 달아봅시다 》
바이패스(Bypass)/ 디커플링(Decoupling)  콘덴서란?
  HC12 모듈과 가까운(멀지 않은) 위치에 노이즈 제거 및 회로 전원 안정화를 위해 아래 회로처럼 콘덴서를 달아 주면 도움이 됩니다.  이런 용도의 콘덴서를 바이패스(Bypass) 콘덴서 또는 디커플링 콘덴서(Decoupling Capacitor)라고 칭합니다.  노이즈와 같은 신호는 때때로 하나의 제대로 된 신호로 인식하게 되고, 그래서 노이즈로 인해 오작동이나 결과에 영향을 주게 됩니다.  그리고 노이즈와 같은 신호는 주파수가 높아서 콘덴서를 통해 그라운드(GND)로 흘려버릴 수 있습니다(ByPass),
  그리고 바이패스/디커플링 콘덴서는 IC나, IC가 들어간 모듈 회로에 순간적으로 전류가 크게 흐르면 손상을 입을 수 있는데 이를 막아주는 역할도 합니다.  그리고 신호(직류 성분)에서 노이즈 성분(교류성분)만 GND로 통과시킨다고 하여 Bypass,  또는 신호(직류성분)에서 노이즈(교류 성분)를 분리해 낸다고 하여 디커플링이라 칭하고 있기 때문에,  기본적으로 같은 개념이며,  용어 또한 혼용해서 사용하고 있습니다. 

  또 한 가지 기능으로 각 부품이나 모듈에 순간적으로 전압(전류) 부족 현상이 생길 수 있는데, 콘덴서에 충전된 전압으로 인해 보충해 주는 역할도 하게 되어,   여러모로 도움이 될 수 있습니다.   여기에 사용되는 콘덴서로는, 무극성(극성 구분이 없는)의 세라믹 콘덴서와 이보다 용량이 큰 유극성의 전해 콘덴서를 주로 사용합니다. 
 굳이 콘덴서 구분을 하자면, 
  - 수백KHz~ 수십MHz의 높은 주파수 노이즈 바이패스 용도로  0.01~0.1uF 용량의 세라믹 콘덴서를 사용하며, 
  - 수Hz~ 수십KHz의 낮은 주파수 노이즈 바이패스 용도로 10~1000uF 용량의 전해 콘덴서를 사용하게 됩니다.
따라서 일부 노이즈에 취약한 특정 회로에서는 모든 노이즈 주파수에 대응하기 위해 세라믹과 전해 콘덴서 함께 사용하기도 합니다. 
  하지만 본 회로에서는 10uF 정도의 전해 콘덴서 하나 넣는 것으로 예시를 들었으며,   
이번 실험을 위해 반드시 달아야 하는 것은 아니니, 콘덴서 부품이 없으신 분들은 그냥 진행하시기 바랍니다. 

바이패스(Bypass)/디커플링/전원 안정화용 콘덴서 부착 회로 모습



▶ 실습 준비 
 - HC12 모듈은 구매 시 대부분 핀이나 안테나의 연결이 되어 있지 않은 상태입니다. 따라서 납땜을 위한 인두기가 필요할 수 있습니다.   납땜 작업 시, 핀의 납땜 방향과 안테나의 납땜 위치를 꼭 확인하고 진행하세요.  또한 납땜 과정에서 인두기로 인해 인접한 부품이 손상될 수 있으니 주의하세요.
 - 기본 제공되는 스프링과 연결핀 납땜한 모습 (작업 상황에 따라 'ㄱ자' 꺾인 핀을 사용하거나 안테나를 눕혀 납땜하여도 무방 합니다. 모두 안테나의 기능을 하는데 문제없습니다. )
 - 위 회로 두 개를 준비합니다.  (아두이노 X 2개,  HC12 모듈 X 2개 )
 - HC-12 모듈의 통신방식은 소프트웨어 시리얼을 이용합니다.  이번 실습에서 하드웨어 시리얼 통신단자(D0, D1)는 PC와의 시리얼 통신에 사용되어 지기 때문이며,  소프트웨어 시리얼 통신 단자는 D2 , D3 뿐 아니라 다른 디지털 단자를 연결하여도 됩니다. (코드 수정 필요)
 

▶ 아두이노 코드 
(아래 코드  아두이노 A / B 두 회로는  코드가 동일합니다.)

《아두이노 A 회로용 코드》 

// ###  'A'회로와 'B'회로 코드 ###  
// 시리얼 모니터를 통한 시리얼 통신 실습입니다.
// HC12모듈을 연결한 동일한 회로 두 개를 준비합니다 (아래 링크 참조)
// RasINO IoT : https://rasino.tistory.com/326

#include <SoftwareSerial.h> 
SoftwareSerial HC12(2, 3); // 아두이노 2번을 HC-12 TX Pin에 연결, 3번을 HC-12 RX Pin에 연결.
void setup() { 
  Serial.begin(9600); // Computer ↔ 시리얼포트(아두이노) 통신속도 
  HC12.begin(9600);   //             시리얼포트(아두이노) ↔ HC12   통신속도 
  Serial.println("This is 'A' HC-12 Module");   // 2번째 아두이노 코드는 'B'로 변경 
} 
void loop() { 
  // 시리얼모니터로 수신(입력)데이터가 있을 경우 HC12를 통해 데이터를 발송  
  while (Serial.available()) { 
    String input = Serial.readString();
    HC12.println(input);
  } 
  // HC12모듈이 받은 데이터가 있을 경우 시리얼모니터로 출력
  while (HC12.available()) { 
    String input = HC12.readString();
    Serial.println(input);
  } 
  delay (20);
}



《아두이노 B 회로용 코드》 

// $$$  'B' HC-12 모듈  $$$
// 시리얼 모니터를 통한 시리얼 통신 실습입니다.
// HC12모듈을 연결한 동일한 회로 두 개를 준비합니다 (아래 링크 참조)
// RasINO IoT : https://rasino.tistory.com/326

#include <SoftwareSerial.h> 
SoftwareSerial HC12(2, 3); // 아두이노 2번을 HC-12 TX Pin에 연결, 3번을 HC-12 RX Pin에 연결.
void setup() { 
  Serial.begin(9600); // 시리얼포트 ↔ computer 
  HC12.begin(9600);   // 시리얼포트 ↔ HC12 
  Serial.println("This is 'B' HC-12 Module");
} 
void loop() { 
  // 시리얼모니터로 수신(입력)데이터가 있을 경우 HC12를 통해 데이터를 발송
  while (Serial.available()) { 
    String input = Serial.readString();
    HC12.println(input);
  } 
  // HC12모듈이 받은 데이터가 있을 경우 시리얼모니터로 출력
  while (HC12.available()) { 
    String input = HC12.readString();
    Serial.println(input);
  } 
  delay (20);
}


 《 위 코드 다운로드 》
아래 파일을 다운로드하여 압축을 풀어보면, 두 개의 파일이 나옵니다.  A 파일은 아두이노 회로 하나에 업로드하고, B 파일은 나머지 아두이노 회로에 업로드합니다.  하지만 실행되는 코드 내용은 같기 때문에 A나 B파일 하나만 가지고 양쪽 모두에 업로드해도 상관없습니다.  하지만, 실행 과정에서는 각각의 A, B 파일이 따로 존재해야 실습을 진행할 수 있습니다.

(실습 1) Serial Communication.zip
0.00MB


▶ 실행 방법 및 결과

: 코드를 업로드 후 아래 순서로 진행하세요. (HC12 모듈을 연결한 아두이노 회로 하나를 편의상 'A'회로라고 하고 동일한 나머지 아두이노 회로를 'B'회로라고 부를게요.)

1.  'A 회로'를 PC의 USB에 연결합니다.  인식된 포트를 확인하고  업로드할 때 사용하였던 A 아두이노 코드를 열고, 보드(나노) 정보를 선택한 다음, 아두이노 나노가 인식된 포트를 선택해 줍니다. 
2. 이어서, 'B 회로'를 PC의 USB에 연결합니다.  인식된 포트를 확인하고  B 아두이노 코드를 직접 클릭해서 여세요. 
보드(나노) 정보를 선택한다음, 아두이노 나노가 인식된 포트를 선택해 줍니다. 

※ 주의 : 일반적으로 윈도 PC에서 시리얼 포트로 아두이노를 두 개까지 포트를 구분해서 인식할 수 있습니다.  
즉, 장치 자체는 인식하고 코드 업로드도 가능하나, 서로 다른 포트로 할당받는 것은 두 개까지만 가능하다는 말입니다.

★☆★ 아두이노 두 개를 하나의 PC에서 서로 다른 시리얼 포트로 인식시키는 방법 ★☆★
 주의해야 할 것은,  A회로 코드를 열었던 아두이노 IDE의 파일 메뉴에서 '열기' 메뉴로 'B'아두이노 파일을 추가로 열게 되면 아두이노-IDE를 두 개 열어도 둘 다 하나의 포트 쪽으로만 인식이 되는 문제가 생길 수 있습니다.
 비록 화면에 뜬 아두이노 IDE 코드 파일은 두 개로 열려 있으나,  아두이노 회로 두 개를 같이 물려보면, 두 회로 모두 동일한 포트 번호로만 할당됩니다.   그러면, 포트 번호가 같기 때문에 아두이노 회로는 한 번에 하나씩만 동작되어서, 
하나의 PC에서 두 회로 간 통신 실험을 진행할 수 없게 됩니다.  따라서,  파일 탐색 창을 열고 'A 아두이노 파일'과 'B 아두이노 파일'을 각각 마우스 클릭으로 열어야 합니다.   그래서 아두이노 두 대를 연결해보면 서로 다른 포트로 할당받게 되고, PC 하나로 원격으로 이루어지는 것과 같은 시리얼 통신 실험을 해볼 수 있게 됩니다.  ( 두 대까지만 가능!  두 대 이상 연결 시에는 한 대를 제외한 나머지 보드는 같은 포트로 중복인식됨)

3.  아래 이미지처럼, 화면에 'A회로 시리얼 모니터 창'과  'B회로의 시리얼 모니터 창' 두 개를 나란히 여세요.
(반드시 포트 번호가 서로 다르게 되어 있는지 확인해 주세요)

이미지를 클릭하면 확대 됩니다

4. 각각의 시리얼 모니터 창을 여세요. 
(시리얼 모니터 창에 표시된 보드 레이트 Baud Rate가 코드와 같은 9600 bps로 되어 있는지 확인하세요)


(아두이노 연결)  두 개 이상은 같은 포트 번호로 할당받게 되어 구분이 되지 않게 됩니다. 
(동작 화면)  동작은 아래처럼 A-Nano 회로가 연결된 시리얼-모니터 입력창에 문자를 입력하면,  B-Nano 회로가 연결된 시리얼-모니터 화면으로 출력됩니다.   그리고,  양방향 통신이 가능한 모듈이고 코딩도 양방향이 되도록 해 두었기 때문에,  반대로 B-Nano 회로의 시리얼-모니터 입력창에 문자를 입력하면, A-Nano 회로가 연결된 시리얼-모니터 화면으로 출력되는 것을 볼 수 있습니다.

▶ 동작 영상
(본 글 제일 아래 전체 동영상을 참고해보세요 : 음성 설명 있음)

 

【  실습  #2 】 무선 RF로 여러 곳의 LED를 On/Off 하기

: 무선으로 멀리 떨어진 곳의 LED 들을 On/Off , 켜고 끄는 실습입니다.   지금은 LED를 예시로 들지만, 무선으로 LED를 제어할 수 있다는 뜻은 전등이 되었든 모터가 되었든 필요한 부가 장치만 달아주면 충분히 제어할 수 있음을 의미합니다.  예를 들어, 220V로 동작하는 전등을 무선으로 On/Off 하고 싶다면, 릴레이 모듈을 추가해주면 쉽게 해결할 수 있습니다.   

아래 회로 연결도를 구성해 주고 PC와 연결합니다.
▶ 회로 연결도 
(아두이노 나노와 RF 무선통신 모듈 HC12 연결도)
《 실습 2 :  A-Nano 기본회로 》

(실습2) A-Nano 기본회로

  
《 실습2 : B-Nano LED 회로 》

《 실습2 : B-Nano LED 회로 》

▶ 실습 준비 :
 위의 회로 두 가지를 준비해주세요.    LED의 색과 크기는 상관없으며, + , - 극성만 잘 구분해서 연결해주세요. 
저항 역시, 100옴~470옴 사이의 저항 값이면 어느 값이든 사용할 수 있습니다.  저항이 작을수록 LED 빛이 더 밝아지며, 저항 값이 클수록 조금 더 어두워지는 차이가 날 뿐입니다.   하지만, 1K옴이 넘어가게 되면 LED를 켤 수 있는 전류를 공급할 수 없어 LED의 동작 확인이 안 될 수 있습니다.
회로는 송신 회로 'A 하나'와,   수신 'LED 회로' 1개 또는 그 이상을 준비할 수 있습니다. 

▶ 아두이노 코드 
(아래 코드  아두이노 A와 / B회로의 코드를 각각 구분해서 업로드하세요.)

《아두이노 A 회로용 코드》 

// ###  'A' HC-12 모듈   ###
// 시리얼 통신실습 2편 - 시리얼 모니터 문자 입력으로 LED 제어하기!
// HC12모듈을 연결한 동일한 회로 두 개를 준비합니다 (아래 링크 참조)
// RasINO IoT : https://rasino.tistory.com/326

#include <SoftwareSerial.h> 
SoftwareSerial HC12(2, 3); // 아두이노 2번을 HC-12 TX Pin에 연결, 3번을 HC-12 RX Pin에 연결.
void setup() { 
  Serial.begin(9600); // Computer ↔ 시리얼포트(아두이노) 통신속도 
  HC12.begin(9600);   //             시리얼포트(아두이노) ↔ HC12   통신속도 
  Serial.println("This is 'A' HC-12 Module");   
} 
void loop() { 
  // 시리얼모니터로 수신(입력)데이터가 있을 경우 HC12를 통해 데이터를 발송  
  while (Serial.available()) { 
    String input = Serial.readString();
    HC12.println(input);
  } 
  // HC12모듈이 받은 데이터가 있을 경우 시리얼모니터로 출력
  while (HC12.available()) { 
    String input = HC12.readString();
    Serial.println(input);
  } 
  delay (20);
}


《아두이노 B , C , D 회로용 코드》 
B회로 하나만 가지고 실습할 수 있으며, 만약 C, D회로를 추가로 늘릴 경우에는 아래 코드에서 비교문 부분에
L1\r\n,   L2\r\n,   L3\r\n 과 같은 부분만 바꾸어서 업로드하면 됩니다.

// $$$  'L1' HC-12 모듈  $$$
// RasINO IoT : https://rasino.tistory.com/
#define LED_L1 5
#include <SoftwareSerial.h> 
SoftwareSerial HC12(2, 3); // HC-12 TX Pin, HC-12 RX Pin 

void setup() { 
  Serial.begin(9600); // Computer ↔ 시리얼포트(아두이노) 통신속도
  HC12.begin(9600);   // 시리얼포트(아두이노) ↔ HC12   통신속도
  Serial.println("This is 'L1' HC-12 Module");
  pinMode(LED_L1,OUTPUT);
  digitalWrite(LED_L1,LOW);  
} 
void loop() { 
  // 시리얼모니터로 수신(입력)데이터가 있을 경우 HC12를 통해 데이터를 발송
  while (Serial.available()) { 
    String input = Serial.readString();
    HC12.println(input);
  } 
  // HC12모듈이 받은 데이터가 있을 경우 시리얼모니터로 출력
  while (HC12.available()) { 
    String input = HC12.readString();
    Serial.println(input);    
    if ( input == "ON\r\n" || input == "L1\r\n" )  { //공백 구분함, line ending없음으로 설정(엔터구분) 
      for (int i=0;i<10;i++) {
        digitalWrite(LED_L1,HIGH);
        delay(200);        
        digitalWrite(LED_L1,LOW);        
        delay(200);        
      } 
    } 
  } 
  delay (20);
}

 《 위 코드 다운로드 》
아래 파일을 다운로드 해서 압축을 풀어보면 아래 파일 4개를 들어 있으며, 필요한 파일만 사용하면 됩니다.

(실습 2) RF 통신 with LED.zip
0.00MB
위 압축파일 속에 이와같은 4개의 파일이 있습니다

▶ 동작 실행(방법)
:  A회로의  아두이노-IDE의 시리얼 모니터 창을 열고 커맨드 입력란에 아래와 같이 입력해보세요.
 -  L1  입력   L1 회로(B회로)의 LED가 10회 깜빡입니다. 
 -  L2  입력 →   L2 회로(C회로)의 LED가 10회 깜빡입니다. 
 -  L3  입력 →   L3 회로(D회로)의 LED가 10회 깜빡입니다. 
 -  ON 입력 →   L1, L2, L3 회로의 모든 LED가 10회 깜빡입니다.


코드에서 중요한 부분을 설명드리면,   시리얼 모니터 입력창을 통해 입력한 문자는 L1  또는 ON이라는 문자만 입력되는 것이 아니라, 눈에는 보이지 않지만,  엔터키를 누르기 때문에(전송 버튼 누름도 마찬가지)  줄 바꿈에 해당하는 개행 문자가 입력되게 됩니다.   따라서 이 개행 문자도 함께 비교해 주어야 코드의 if 비교문이 제대로 작동합니다. 

엔터입력하면 개행문자(\r\n) 입력됨

 따라서  아래와 같은 코드 형태로 비교해 주어야 합니다. 
if ( input == "ON\r\n" || input == "L1\r\n" )   { ...  }

또한, 아래처럼, 시리얼 모니터창의 입력 옵션을 line ending 없음으로 해야,  개행 문자 처리가 중복으로 되지 않아 제대로 처리됩니다. 

 

 마지막으로 중요한 한 가지는, 아두이노와 같은 C/C++ 언어 프로그래밍에서 개행 문자의 처리가 운영체제 별로 다르다는 데 있습니다. 
최근에는 아두이노 코딩 환경을 윈도 환경에서 뿐 아니라, 리눅스나 맥 OS 환경에서 많이 하는 것을 볼 수 있는데요,
아래 운영체제 별 개행 문자 처리를 참고하여,  코드에 반영해 주어야 합니다.  ( '\' 표시는 역슬래시입니다)
 → Windows OS 개행 문자 :   \n\r
 → Mac OS 개행문자        :   \r
 → Linux 개행문자           :   \n

 

▶ 동작 영상
(본 글 제일 아래 전체 동영상을 참고해보세요 : 음성 설명 있음)

 

【 센서 실습  #3 】  LED의 밝기를 무선으로 조절하기(with VAR)

: 실습 #3에서는 가변저항 또는 볼륨으로 불리는 VAR(Variable resistor, 또는 Potentiometer)을 이용하여 원격지에 있는 회로의 LED의 밝기를 조절해 보는 실습입니다. 
 또한, VAR 쪽의 송신부에도 LED를 달아서 VAR 값의 변화가 제대로 되는지? 먼저 확인할 수 있도록 하였습니다

▶ 회로 연결도 (VAR이 연결된 회로와 LED 수신 회로 두 가지를 만드세요)
《 회로 1 :  VAR - Nano 송신 회로 》

《 회로 2 :  VAR - Nano 송신 회로 》


▶ 실습 준비 :
 위의 회로 두 가지를 준비해주세요.  가변저항은 여러 가지 종류가 있으며, 어떤 종류를 사용하더라도 사용이 가능합니다. 용량 또한,  1K옴~1M옴 사이의 용량이면 회로를 구성하는데 크게 문제없습니다. (권장, 1K옴~10K옴 사이)

여러가지 가변(반고정) 저항의 종류들

 본격적인 실습 전에,  가변저항의 역할과 활용에 대해 설명드립니다. 

- VAR의 ①번과 ③번 양단에 5V의 전압을 넣어 주면, ②번 단자로 전압이 나오게 되는데요,
VAR 조절 레버를 ①번 끝에서 ③번 끝까지 돌림에 따라, ②번으로 5V~0V 사이의 전압이 출력됩니다.
그리고, VAR의 ②번 단자 출력을 아두이노의 아날로그 입력 단자로 연결하였는데요,
아두이노 내부의 아날로그 입력 단자들에 연결된 AD Converter(Analog to Digital)에 의해 '0~5V'라는 아날로그 값이,  '0~1023'라는 디지털 수치로 변환되어 전달받게 됩니다.
나노(우노)에 내장된 ADConverter는 10bit의 분해능을 갖고 있어 최댓값은 2의 10승 값인 1024가 됩니다.
그리고 아두이노의 출력 단자는 디지털 단자여서 기본적으로 Low(0v)와 High(5v)의 값만 출력되는데요
LED의 밝기를 조절하려면, 0v~5v 사이의 아날로그 값이 필요합니다.

아두이노의 디지털 단자 중에서 아날로그와 같은  출력을 대신해 주는 단자가 PWM 출력 단자인데요.
High와 Low신호의 출력 비율(Duty Cycle)을 조절하여, 출력 전압이 조절되는 효과를 얻을 수 있습니다

아두이노에서는 디지털 단자의 숫자 옆에 '~'물결 기호가 붙어 있는 단자가 바로 PWM기능이 있는 디지털 단자입니다
( ※ Uno와 Nano의 PWM 단자: D3 ,D5, D6, D9, D10, D11 )

~ 물결무늬가 있는 핀이 PWM 출력 기능이 있는 핀입니다

아두이노의 아날로그 입력이 어떻게 디지털 값으로 변환되고 다시 아날로그 형태(디지털 PWM)로 출력되는지 아래 이미지와 함께 설명드리면, 
 나노(우노) 보드의 PWM 포트 출력은 8bit로 처리되기에, 2의 8승 값인, 0~255 사잇값으로 출력됩니다

그런데, A0로 입력된 값은 0~1023 값이고, 출력할 수 있는 최대 범위는 0~255이기 때문에, 입·출력의 매칭이 필요한데요, 아두이노 코드에서 맵핑 함수를 사용하면 간단히 해결할 수 있습니다

0~1023의 범위 값을 0~255값으로 맵핑하는 함수 사용

이렇게 해서 VAR가변저항을 돌려 변화되는 아날로그 입력 전압이(0~5V) 나노의 High(5V), Low(0v) 기능만 할 수 있던 디지털 출력 포트로 PWM 기능을 사용하여 0~5v의 변화되는 출력을 낼 수 있게 되어 LED의 밝기 조절이 가능해집니다. 


▶ 아두이노 코드 
( 아래의 코드 두 가지를 구분해서 각각 아두이노에 업로드해주세요. )
《 회로 1 : VAR 회로 코드 》

// VVVVV  HC-12 'VAR-side' 가변저항 회로 코드   VVVVV
// RasINO IoT : https://rasino.tistory.com/
#define LED_L1 5
#include <SoftwareSerial.h> 
SoftwareSerial HC12(2, 3); // HC-12 TX Pin, HC-12 RX Pin 

int Var = 0;

void setup() { 
  Serial.begin(9600); // Computer ↔ 시리얼포트(아두이노) 통신속도
  HC12.begin(9600);   //             시리얼포트(아두이노) ↔ HC12   통신속도
  Serial.println("This is 'VAR controller' HC-12 Module");
  pinMode(LED_L1,OUTPUT);
  digitalWrite(LED_L1,LOW);  
} 
void loop() { 
  Var = map(analogRead(A7), 0, 1023, 0, 255);
  analogWrite(LED_L1, Var);
  Serial.println(Var);  
  HC12.write(Var); // 주의! : 'print()'가 아닌, 'write()'를 사용합니다
  // ※ 'print()'는 숫자의 경우 ASCII값으로 변환하여 전송하기 때문에, 
  // 숫자값 그대로 전송하는 'write()'를 사용합니다
}


《 회로 2 : LED 회로 코드 》

// ### HC-12 'LED-side' 가변저항(LED) 회로 코드   ###
// RasINO IoT : https://rasino.tistory.com/
#define LED_L1 5
#include <SoftwareSerial.h> 
SoftwareSerial HC12(2, 3); // HC-12 TX Pin, HC-12 RX Pin 
void setup() { 
  Serial.begin(9600); // computer ↔ 시리얼포트(아두이노) 통신속도
  HC12.begin(9600);   // 시리얼포트(아두이노) ↔ HC12   통신속도
  Serial.println("This is 'LED' Side HC-12 Module"); 
  pinMode(LED_L1,OUTPUT);
  digitalWrite(LED_L1,LOW);  
} 
void loop() { 
  while (HC12.available()) { 
    int input = HC12.read();
    Serial.println(input);
    analogWrite(LED_L1, input);    
  }   
}


《 위 코드 다운로드 》

(실습 3) Var-LED.zip
0.00MB

▶ 동작 실행(방법)
:  VAR이 연결된 나노 회로의 VAR을 한쪽 끝에서 다른 쪽 끝으로 돌려보면 RF 신호를 수신한 LED 회로의 LED의 밝기가 조절됩니다.  이때 보조배터리와 같은 외부 전원만으로도 동작시킬 수 있으며, PC에 연결해서 실습을 진행할 경우 시리얼 모니터 창을 띄우면, 변환되는 0~255 값을 함께 확인할 수 있습니다.

▶ 동작 모습

▶ 실행 영상
(제일 아래 전체 설명 동영상 참고)

【 실습  #4 】
시리얼 통신#1 (AT-커맨드 명령어 사용하기)

: 실습 #4에서는 AT-커맨드 명령어를 사용하여 HC-12 모듈의 설정을 바꾸어 보겠습니다.  이번 실습 4는 #1편과 #2편으로 구분되어 있습니다.
PC와 연결하고 아두이노-IDE의 시리얼 모니터를 사용하여 AT-통신 명령어를 입력하면, HC-12의 '통신 채널 변경', 'Bauds Rate', '통신 모드'와 같은 설정을 변경할 수 있습니다.  AT-명령어 모드로 진입하기 위해서는, HC12 모듈의 SET 단자가 GND(Low)로 연결되어 있어야 합니다.  

▶ 실습 준비 : 회로는 하나만 준비하면 됩니다.  상호 통신이 아니라 PC와 연결하여 AT  명령어를 이용한 HC-12 모듈의 설정 변경 실습이기 때문에, 회로는 하나를 준비하고,  실습은 2가지로 진행합니다. 

▶ 회로 연결도
《 실습 4-1의 회로 :  Set 핀 - GND 연결된 회로 》

▶ 아두이노 코드 
( 아래의 코드를 업로드해주세요. )
《 실습4-1 회로 코드 》

// ###  'AT-Command'  실습     ###
// AT-명령어를 통하여 HC12의 채널/속도/모드... 등을 변경해 보는 실습
// HC12모듈을 연결한 회로를 준비합니다 (아래 링크 참조)
// RasINO IoT : https://rasino.tistory.com/326

#include <SoftwareSerial.h>
SoftwareSerial HC12(2, 3);

void setup() 
{
  Serial.begin(9600); // Computer ↔ 시리얼포트(아두이노) 통신속도 
  HC12.begin(9600);   //             시리얼포트(아두이노) ↔ HC12 통신속도 
}
void loop() 
{   
  while (Serial.available()) {
    HC12.write(Serial.read());
  }
  while (HC12.available()) {
    Serial.write(HC12.read());
  }
}

《 위 코드 다운로드 》

HC12_AT-Change_CH.zip
0.00MB

▶ 동작 실행(방법)
 :  회로를 구성하고 PC와 연결하여 아두이노-IDE의 시리얼 모니터창을 띄우면, AT-명령어 입력 모드 상태가 됩니다.
AT-명령어 모드로 진입하기 위해서는, HC12 모듈의 SET 단자가 GND(Low)로 연결되어 있어야 합니다.

아래, 많은 시간을 들여 직접 정리한 AT-명령어 표를 참고하여 테스트해보세요. 

- '시리얼-모니터' 입력창에 대문자로 'AT '라고 입력하세요.
  'OK'라는 응답 신호가 나온다면, AT-Command 모드 진입에 성공한 것입니다. 

- 'AT+RX'를 입력하면 현재의 주요 설정값을 한 번에 보여줍니다.
- 그리고,  현재 RC001로 '채널 1'로 설정되어 있는 것을 '채널 2'로 바꾸어 보세요.

- 'FUx'모드 설정을 통해 좀 더 특수한 환경에서 동작할 수 있도록 동작 모드를 변경할 수도 있습니다.
만약, FU2와 FU4 모드를 선택한다면, 시리얼 포트 통신속도는 제한된 속도로 자동 변경됩니다.

만약, FU2와 FU4 모드를 선택한다면, 위 이미지의 FUx 모드 상세 설명에서 처럼, 시리얼 포트 통신속도는 제한된 속도로 자동 변경됩니다.
- 송신 파워 설정도 변경해 보세요.


- 'AT+DEFAULT' 명령어로 바뀐 설정을 한 번에 복구할 수 있습니다

- 마지막으로 HC12 모듈의 셋업 설정이 마무리 하였다면,   SET핀을 GND에 연결하였던 선을 제거해야, 
HC12모듈의 통신이 가능하다는 것을 기억하세요.

 

시리얼 통신#2 (AT-커맨드 명령어 사용하기)

이번 실습 4-1는 셋업을 직접 손으로 SET-GND 핀을 연결하지 않고, 프로그램 코딩으로 아두이노의 아웃풋 출력 단자를  LOW / High 출력으로 조절하여 설정하는 실습입니다.   손이 아닌, 코드로 셋업을 조절하게 되면, 채널 변경이나, 모드 변경 등과 같은 기능들을 코드나, 스위치 조작 등 더 다양하게 활용할 수 있게 됩니다. 
▶ 회로 연결도

《 실습 4-2의 회로 :  Set 핀 - 디지털 입출력 핀 연결된 회로 》

SET 핀의 아두이노 포트 연결은 아무 디지털 출력 포트로 선택하면 됩니다.  여기서는 D6번 핀으로 하였고, 코드에도 6번으로 되어 있으니 변경하려 한다면, 코드의 핀 번호를 수정하세요.

▶ 아두이노 코드 
( 아래의 코드를 업로드해주세요. )
《 실습 4-1 회로 코드 》

// ###  'AT-Command'  실습     ###
// HC12 모듈의 Setup Pin을 활용한 HC12의 채널/속도/모드... 변경 실습 
// HC12모듈을 연결한 회로를 준비합니다 (아래 링크 참조)
// RasINO IoT : https://rasino.tistory.com/326

#include <SoftwareSerial.h>
SoftwareSerial HC12(2, 3);
#define setPin 6  // HC12 모듈의 SET 핀에 연결될 아두이노 핀 번호 정의 함

void setup() 
{
  Serial.begin(9600);
  HC12.begin(9600);
  pinMode(setPin,OUTPUT);
  digitalWrite(setPin,LOW);  //  AT command mode 진입
  delay(100);                // 명령어 전달되는 시간을 기다려 줌 
  HC12.write("AT");          // AT 명령어 입력 ( "OK" 문자 응답)
  delay(300);                // 명령어 전달되는 시간을 기다려 줌 
  HC12.write("AT+C003");       // 현재 HC12의 설정 정보를 보여달라는 명령
  delay(300);                // 명령어 전달되는 시간을 기다려 줌   
  HC12.write("AT+FU2");       // 현재 HC12의 설정 정보를 보여달라는 명령
  delay(300);                // 명령어 전달되는 시간을 기다려 줌   
  digitalWrite(setPin,HIGH); // AT-mode 빠져나옴(data 전송모드)
}

void loop() 
{ 
  while (HC12.available()) {
    Serial.write(HC12.read());
  }  
  while (Serial.available()) {
    HC12.write(Serial.read());
  }

}

《 위 코드 다운로드 》

HC12_AT-Use_Setup_pin.zip
0.00MB

▶ 동작 실행(방법)
 :  회로를 아래와 같이 구성하고 PC와 연결하여 아두이노 코드를 업로드하면, 코딩 루틴에 의해 자동으로 채널이 001번 채널에서 002번 채널로 변경되게 됩니다.  

 그럼, 코딩에 의해 자동으로 채널이 변경된 것인지? 확인하기 위해,  그래서 AT 모드로 진입하기 위해 다시 아래처럼, 6번 핀에 연결된 SET-핀을 뽑고,  직접 GND에 연결해 주세요. 

그리고, 아두이노-IDE의 시리얼 모니터 창을 열어 AT+RX 명령어로, 설정 상태를 확인해보면, 채널이 002번 채널로 변경되어 있는 것을 확인할 수 있게 됩니다.
▶ 동작 모습

그럼, 코드를 수정해서, 다른 AT-명령어도 넣어서 적용해 보세요.  (아래는 예시입니다)


이렇게, SET핀을 아두이노 포트로(코드로) 제어하게 되면, 이어지는 실습에서처럼, 버튼으로 채널을 변경하거나, 통신 모드 변경과 같은 것을 쉽게 구현할 수 있습니다.

【 실습  #5 】  무선 버튼으로 통신채널 변경하기

: 실습 #5에서는 '버튼 1'을 누르면, 통신채널 1번으로 동기화되고, '버튼 2'를 누르면, 통신채널 2번으로 동기화되는 실습입니다.  실습#4를 응용한 실습인데요, 버튼 수를 늘려서 변경되는 채널 수를 늘릴 수도 있고, 통신 모드 변경이나 파워 설정 같은 AT모드상에서 변경할 수 있는 것들을 이번 실습을 통해 쉽게 적용시킬 수 있습니다.  

▶ 실습 준비 : 회로는 두 가지를 준비합니다.  버튼(스위치) 2개가 들어간 1번 회로와,  신호를 수신하여 적용되었다는 것을 알 수 있도록 LED를 연결한 2번 회로로 구성됩니다.    또한, 무선 RF의 장점인 채널이 일치하면 1대 N의 통신이 가능함을 보여드립니다.  이 때는 똑같이 적용된 2번 회로가 2개 이상 필요합니다.  기본적으로, 2번 회로 하나만 있어도 실습 5의 학습은 가능합니다. 

[ 회로에 사용된 푸시버튼스위치(PB-SW) 설명 ] 
 아두이노에서 PB-SW는 보통 High 신호와 Low 신호를 입력하고자 할 때 사용하게 되는데요, 
스위치 한쪽을 GND로 연결하고, 나머지 한쪽은 저항을 통하여 VCC로 연결하게 되는데요, 
버튼을 누를 때는 GND로 연결되기 때문에, Low 신호가 아두이노 포트에 입력되며,
버튼을 누르지 않았을 때는 GND와 분리되고, 저항을 통해 VCC로 연결되기 때문에 High 신호가 입력됩니다. 
이때, 저항의 역할은 기본적으로 스위치를 누를 때 GND와 VCC가 합선(Short)되는 것을 방지하고, 누르지 않았을 때는, 확실한 High 신호를 입력되게 하는 역할로 사용되며, 이런 저항의 역할을 바로 풀업(Pull UP) 저항이라 합니다. 
이와 반대되는 개념의 저항을 풀다운(Pull Down) 저항이라 합니다. 

외부 풀업저항 연결

위, 이미지에서 스위치를 닫으면 GND(그라운드, 혹은 0V)에 연결되어 Low 신호가 아두이노의 D5번 포트로 입력되게 되며, 스위치를 오픈하면, 5V의 High 신호가 저항을 타고 D5로 입력되는 구조입니다.    여기서  만약에 저항을 연결하지 않고 직접 5V 전원을 D5로 연결시킬 경우, 스위치를 닫을 때, GND와 5V가 직접적으로 맞닿아 합선(Short)되어 문제가 생기게 되어 저항이 필요하며,   만약 저항과 5V 연결 자체를 하지 않게 될 경우, 스위치를 닫을 때는 확실한 Low신호가 입력되나, 스위치를 오픈할 경우에는 확실한 High 신호가 입력되지 않아 불안정해집니다.  따라서, 이런 이유 때문에 스위치와 함께 사용하게 되는 저항을 일컫어,  확실하게 +전원(5V, VCC)으로 끌어올린다(당긴다)하여, Pull UP 저항이라 칭합니다.   마찬가지로, 아래와 같은 연결의 저항을 풀 다운 저항이라 칭합니다. 

풀 다운(Pull Down) 저항과 스위치의 연결

그런데,  아두이노를 설계할 때, 각 포트마다 스위치를 연결할 경우 필요한 풀업 저항의 연결을 최소화하고자 하는 목적으로 내부 풀업 저항이 설계되어 있습니다. 

따라서, 외부에 별도의 풀업용 저항을 연결할 필요 없으니 회로 구성을 더욱 간단히 할 수 있어 편합니다. 
그럼, 풀업 저항의 기능을 활성화하기 위해서는 아두이노 코드에서,  해당 포트의 입력을 풀업 기능으로 설정만 해주면 됩니다. 
일반 적으로 아두이노 코드에서 예를 들어, D5번 포트를 입력으로 설정할 경우에는, 
pinMode ( 5, INPUT );   이렇게 작성하나,    풀업 기능의 입력을 사용할 경우에는 
pinMode ( 5, INPUT_PULLUP );   이라고 설정해주면 됩니다. 

▶ 회로 연결도(VAR이 연결된 회로와 LED 수신 회로 두 가지를 만드세요)
《 회로 1 :  버튼스위치(PB-SW) Nano 회로 》
회로 1에서도 버튼을 눌렀을 때, 눌러졌다는 것을 알기 위해 LED를 연결해 놓았습니다.

《 회로 2 :  LED - Nano 회로 》

▶ 아두이노 코드 
( 아래의 코드를 업로드해주세요. )
《 실습 5  버튼 스위치 1번 회로 코드 》

/* 《 버튼으로 통신채널 변환하기 》 --- 1번 Nano (버튼 회로) ---  
 * AT명령어를 수정하면 통신속도(거리)/ 동작(통신)모드 / 슬립모드 / 송신파워 등의 설정이 가능함 
 * 회로의 상세자료 및 설명은 게시글 참조 : https://rasino.tistory.com/326
*/

#include <SoftwareSerial.h>  //소프트웨어 시리얼 연결은 2번, 3번 이외의 비어있는 다른 디지털 핀을 사용해도 됨
SoftwareSerial HC12(2, 3);   // (HC12의 TX Pin, HC12의 RX Pin)을 연결할 아두이노 포트 지정 (2번, 3번)
#define setPin 6    // HC12의 SetPin 연결 (AT모드 진입에 사용되는 핀)  
#define btn1 5      // '버튼 1' 연결
#define btn2 9      // '버튼 2' 연결 
#define led 12      // 버튼을 누를 때 확인하기 위한 LED 연결

byte incomingByte;        // 수신 데이터를 바이트 단위로 저장하는 변수 선언
String readBuffer = "";   // 송·수신 데이터 저장을 위한 문자열 변수 선언
int btn1_State = 0;       // 버튼 1의 상태
int btn1_Pressed = 0;     // 버튼 1의 눌러짐 체크 변수
int btn2_State = 0;       // 버튼 2의 상태  
int btn2_Pressed = 0;     // 버튼 2의 눌러짐 체크 변수

void setup() {
  Serial.begin(9600);           // PC와의 시리얼 통신 포트 열기(시작)
  HC12.begin(9600);             // HC12의 시리얼 포트 열기(시작)
  pinMode(setPin, OUTPUT);      // HC12의 AT 모드 진입을 위한 아두이노 연결핀 출력설정
  pinMode(btn1, INPUT_PULLUP);  // 버튼 1을 저항 연결 없이 내부 풀업을 사용하여 연결함
  pinMode(btn2, INPUT_PULLUP);  //     2를 
  pinMode(led, OUTPUT);         // 버튼 입력 표시를 위한 LED 연결  
  digitalWrite(setPin, HIGH);   // HC-12를 일반적인 전송 모드로 설정함 (LOW 일경우 AT 커맨드 모드로 진입함)
  digitalWrite(led,LOW);        // LED OFF로 디폴트 설정
  Serial.println("This is ** Nano1 ** , i'm ready!");
}

void loop() {
  // 문자열 변수 버퍼에 HC12의 수신 데이터 저장
  while (HC12.available()) {             // HC12에 데이터가 있다면
    incomingByte = HC12.read();          // HC12로 부터 바이트(byte) 단위로 읽어 byte타입 변수에 저장
    readBuffer += char(incomingByte);    // 각각의 읽은 바이트를 문자열 변수에 저장 (예시, 'A' 'T' '+' 'R' 'X' → "AT+RX")
  }
  delay(100);
  // 시리얼 데이터가 있을 경우 HC12(1번 nano)의 데이터를 외부 다른 HC12(2번 nano)로 발신
  while (Serial.available()) {
    HC12.write(Serial.read());
  }

// 〔 #####  버튼1이 눌러지면, HC12의 채널을 '001'로 설정하는 루틴의 시작 ##### 〕

  btn1_State = !digitalRead(btn1);    // 버튼의 하드웨어 연결이 누르면 LOW, 떼면 HIGH 입력되므로, '!'로 반전 값 저장함
  if (btn1_State == HIGH & btn1_Pressed == LOW) {   // 만약 버튼1이 눌러지고, 버튼1 눌러짐 체크 변수가 LOW 였다면
    btn1_Pressed = HIGH;            // 버튼1 눌러짐 체크 변수를 HIGH로 함                 
    delay(20);
  }
  if (btn1_Pressed == HIGH) {            // 만약 버튼1 눌러짐 체크 변수가 HIGH 라면,    
    digitalWrite(led, HIGH);             // LED를 켜고  
    HC12.print("AT+C001");               // 다른(nano_2번) HC12모듈에 채널 1로 변경하는 신호 발신
    delay(100);                          // 신호 발신 시간 기다려줌
    // AT 명령어 모드로 진입하는 루틴 시작 (nano_1번)
    digitalWrite(setPin, LOW);           // HC12의 Set핀에 LOW를 입력하여, AT 커맨드(명령어) 모드로 진입함
    delay(100);                          // 시간 딜레이
    HC12.print("AT+C001");               // 채널 1로 변경하는 AT 명령어 보냄
    delay(200);                          // 명령어 적용되는 시간 딜레이
    while (HC12.available()) {           // HC12에 데이터(여기선, AT-명령어 응답 신호)가 있는지가 있는지 체크하여 
      Serial.write(HC12.read());         // 데이터를 시리얼 모니터로 전송
    }
    Serial.println("btn 1 pressed, changing Channel 《 No.1 》");
    digitalWrite(setPin, HIGH);          // 셋핀을 HIGH로 입력하여 AT 커맨드 모드를 빠져나옴
    digitalWrite(led, LOW);              // 버튼을 누를때 켰던 LED를 끔
    btn1_Pressed = LOW;                  // 버튼 눌러짐 체크 변수를 LOW로 함 
  }
// ######################################
  
// 〔 $$$$$  버튼2가 눌러지면, HC12의 채널을 '002'로 설정하는 루틴의 시작 $$$$$ 〕
  btn2_State = !digitalRead(btn2);
  if (btn2_State == HIGH & btn2_Pressed == LOW) {
    btn2_Pressed = HIGH;
    delay(100);
  }
  if (btn2_Pressed == HIGH) {       // 만약 버튼2 눌러짐 체크 변수가 HIGH 라면,  
    digitalWrite(led, HIGH);        // LED를 켜고
    HC12.print("AT+C002");          // 다른(nano_2번) HC12모듈에 채널 2로 변경하는 신호 발신
    delay(100);
    // AT 명령어 모드로 진입하는 루틴 시작 (nano_1번)
    digitalWrite(setPin, LOW);      // HC-12의 Set핀에 LOW가 입력되면, AT 커맨드(명령어) 모드로 진입함
    delay(100);                    
    HC12.print("AT+C002");          // 채널 2로 변경하는 AT 명령어 보냄
    delay(200);
    while (HC12.available()) {      // HC12에 데이터(여기선, AT-명령어 응답 신호)가 있는지가 있는지 체크하여 
      Serial.write(HC12.read());    // 데이터를 시리얼 모니터로 전송
    }
    
    Serial.println("btn 2 pressed, changing Channel 《 No.2 》");
    digitalWrite(setPin, HIGH);     // 셋핀을 HIGH로 입력하여 AT 커맨드 모드를 빠져나옴
    digitalWrite(led, LOW);         // 버튼을 누를때 켰던 LED를 끔
    btn2_Pressed = LOW;
  }
  checkATCommand();                // AT 명령 응답신호 체크함수 호출 
  readBuffer = "";                 // 버퍼를 비움
}

// 시리얼모니터를 통해 AT 명령어를 잘 전달 받았는지, 체크하는 서브함수
void checkATCommand () {
  if (readBuffer.startsWith("AT")) {     // 버퍼에 'AT'로 시작되는 문자열이 있는지 확인
    digitalWrite(setPin, LOW);           // HC-12를,  AT 커맨드 모드로 진입
    delay(100);                          // 시간 딜레이
    HC12.print(readBuffer);              // 버퍼에 있는 내용을 HC12로 보냄
    delay(200);                          // 시간 딜레이
    while (HC12.available()) {           // HC12에 AT-응답 신호가 있는지가 있는지 체크하여 
      Serial.write(HC12.read());         // 시리얼 모니터로 전송
    }
    digitalWrite(setPin, HIGH);          // AT 명령어 모드를 빠져나옴
  }
}

《 위 코드 다운로드 》

btn_SW_One.zip
0.00MB


《 실습5  LED 2번 회로 코드 》

/* 《 버튼으로 통신채널 변환하기 》 --- 2번 Nano (LED 회로) ---  
 * AT명령어를 수정하면 통신속도(거리)/ 동작(통신)모드 / 슬립모드 / 송신파워 등의 설정이 가능함 
 * 회로의 상세자료 및 설명은 게시글 참조 : https://rasino.tistory.com/326
*/

#include <SoftwareSerial.h>
SoftwareSerial HC12(2, 3);  // (HC12의 TX Pin, HC12의 RX Pin)을 연결할 아두이노 포트 지정 (2번, 3번)
#define setPin 6     // HC12의 SetPin 연결 (AT모드 진입에 사용되는 핀)
#define led 5        // 채널이 변경 되었음을 표시하기 위해 LED를 연결함

byte incomingByte;          // 수신 데이터를 바이트 단위로 저장하는 변수 선언
String readBuffer = "";     // 송·수신 데이터 저장을 위한 문자열 변수 선언

void setup() {
  Serial.begin(9600);         // PC와의 시리얼 통신 포트 열기(시작)
  HC12.begin(9600);           // HC12의 시리얼 포트 열기(시작)
  pinMode(setPin, OUTPUT);    // HC12의 AT 모드 진입을 위한 아두이노 연결핀 출력설정
  pinMode(led, OUTPUT);       // 버튼 입력 표시를 위한 LED 연결 
  digitalWrite(setPin, HIGH); // HC-12를 일반적인 전송 모드로 설정함 (LOW 일경우 AT 커맨드 모드로 진입함)
  digitalWrite(led,LOW);      // LED를 OFF로 디폴트 설정  
  Serial.println("This is $$ Nano2 $$ , i'm ready!");
}

void loop() {
  // 문자열 변수 버퍼에 HC12의 수신 데이터 저장
  while (HC12.available()) {             // HC12에 데이터가 있다면
    incomingByte = HC12.read();          // HC12로 부터 바이트(byte) 단위로 읽어 byte타입 변수에 저장
    readBuffer += char(incomingByte);    // 각각의 읽은 바이트를 문자열 변수에 저장 (예시, 'A' 'T' '+' 'R' 'X' → "AT+RX")
  }
  delay(100);
  // 시리얼 데이터가 있을 경우 HC12로 발송
  while (Serial.available()) {
    HC12.write(Serial.read());
  }
  
  // ### nano1번의 버튼1이 눌러질 때 전송받은 데이터가 "AT+C001"이라면, 여기 Nano2에서 HC12의 채널을 '001'로 설정하는 루틴  ###
  
  if (readBuffer == "AT+C001") {         // 만약 버퍼에 저장된 데이터가 "AT+001"이라면,
    digitalWrite(led, HIGH);             // LED를 켜고, 
    digitalWrite(setPin, LOW);           // HC12의 Set핀에 LOW를 입력하여, AT 커맨드(명령어) 모드로 진입함
    delay(100);                          // 시간 딜레이
    HC12.print(readBuffer);              // 버퍼에 있는 데이터로(채널 1로 변경하는 "AT+C001") AT 명령어 보냄
    delay(200);                          // 명령어 적용되는 시간 딜레이
    while (HC12.available()) {           // HC12에 데이터(여기선, AT-명령어 응답 신호)가 있는지가 있는지 체크하여 
      Serial.write(HC12.read());         // 데이터를 시리얼 모니터로 전송
    }
    Serial.println("Channel successfully changed, 《 No.1 》");
    digitalWrite(led, LOW);              // LED를 끔 
    digitalWrite(setPin, HIGH);          // 셋핀을 HIGH로 입력하여 AT 커맨드 모드를 빠져나옴
    readBuffer = "";                     // 버퍼를 비움 
  }
  
// ### nano1번의 버튼2가 눌러질 때 전송받은 데이터가 "AT+C002"이라면, 여기 Nano2에서 HC12의 채널을 '002'로 설정하는 루틴  ###
  if (readBuffer == "AT+C002") {        // 만약 버퍼에 저장된 데이터가 "AT+001"이라면, 
    digitalWrite(led, HIGH);            // LED를 켜고
    digitalWrite(setPin, LOW);          // HC12의 Set핀에 LOW를 입력하여, AT 커맨드(명령어) 모드로 진입함
    delay(100);                         // 시간 딜레이
    HC12.print(readBuffer);             // 버퍼에 있는 데이터로(채널 2로 변경하는 "AT+C002") AT 명령어 보냄
    delay(200);                         // 명령어 적용되는 시간 딜레이
    while (HC12.available()) {          // HC12에 데이터(여기선, AT-명령어 응답 신호)가 있는지가 있는지 체크하여
      Serial.write(HC12.read());        // 데이터를 시리얼 모니터로 전송
    }
    Serial.println("Channel successfully changed, 《 No.2 》");
    digitalWrite(led, LOW);             // LED를 끔
    digitalWrite(setPin, HIGH);         // 셋핀을 HIGH로 입력하여 AT 커맨드 모드를 빠져나옴
    readBuffer = "";                    // 버퍼 비움 
  }
  checkATCommand();                     // AT 명령 응답신호 체크함수 호출
  readBuffer = "";                      // 버퍼를 비움
}

// 시리얼모니터를 통해 AT 명령어를 잘 전달 받았는지, 체크하는 서브함수
void checkATCommand () {
  if (readBuffer.startsWith("AT")) {     // 버퍼에 'AT'로 시작되는 문자열이 있는지 확인
    digitalWrite(setPin, LOW);           // HC-12를,  AT 커맨드 모드로 진입
    delay(100);                          // 시간 딜레이
    HC12.print(readBuffer);              // 버퍼에 있는 내용을 HC12로 보냄
    delay(200);                          // 시간 딜레이
    while (HC12.available()) {           // HC12에 AT-응답 신호가 있는지가 있는지 체크하여 
      Serial.write(HC12.read());         // 시리얼 모니터로 전송
    }
    digitalWrite(setPin, HIGH);          // AT 명령어 모드를 빠져나옴
  }
}


《 위 코드 다운로드 》

LED_Two.zip
0.00MB

 

▶ 동작 실행(방법)
 :  SW1을 누르면 채널 1로 설정되고,  SW2를 누르면 채널 2로 설정됩니다.   이때, 코드가 작동되면서 회로 1과 회로 2에 연결된 LED가 점멸하게 됩니다.   아래 이미지처럼, 시리얼 모니터 상에도 채널이 변경된 정보가 뜨도록 처리했습니다.

아래 동작 이미지는 수신 회로 2개를 더 추가하여, 동시에 수신 회로 3개의 채널을 변경되는 것을 보여드리고 있습니다. 

만약, 일부의 채널이 잘 변경되지 않을 경우에는 코드의 delay( )값을 잘 조절해 보거나,   바뀌지 않는 회로의 HC12 모듈의 채널을 확인해 보시기 바랍니다.  채널 변경 실험 과정 등에서, 1 채널 혹은 2 채널이 아닌 아예 다른 채널로 변경되는 경우가 있으니,  이럴 때는, AT통신용 코드를 업로드하여 AT-커맨드 모드에서 채널 확인해보고, 다시 채널을 1번으로 변경하거나, AT+DEFAULT 디폴트로 바꾸어 놓으면 됩니다. 


【 실습  #6 】  RF 무선 조이스틱으로 서보모터 제어하기

: 실습 #6에서는 조이스틱을 이용하여 서보모터 2 개를 무선으로 제어해 보는 실습입니다. 
무선으로 모터 하나를 제어하는 것은 하나의 데이터만 처리하면 됨으로 비교적 쉽지만,  모터 2개를 제어하는 것은 쉽지 않은데요,  시리얼 형태로 날아오는 데이터를 받아서 A 모터 데이터와 B모터 데이터를 구분해서 처리하는 코드 스킬이 필요하기 때문입니다. 
  이번 실습을 통해서 이런 코드 스킬을 익혀둔다면, 다른 작품에도 동일하게 적용할 수 있으니 매우 유익할 것으로 기대됩니다. 



▶ 실습 준비 :   
 회로는 두 가지를 준비합니다.  조이스틱이 연결된 1번 송신 회로와,  서보 모터 2개로 구성된 2번 수신 회로입니다.
서보모터는 SG-90이라는 모터를 사용하였으나, 다른 종류의 서보모터 사용도 가능합니다.
조이스틱의 경우, 제조사에 따라 핀 배열이 본 게시글에서 사용한 것과다를 수 있으니, 갖고 계신 조이스틱의 핀 배열을 확인하고 연결하세요. 


  [ 회로 동작 원리 ] 
조이스틱을 좌우로 움직일 때, VRx로, 전압값(0v~5v)이 나오면, 이를 아두이노의 A0포트로 입력시키고, 
조이스틱을 위아래로 움직일 때, VRy로, 전압값(0v~5v)이 나오면, 이를 아두이노의 A1포트로 입력시키게 됩니다.
그럼, 실습#3 과정에서 설명했듯이, 나노(우노)에서는 10bit의 분해능을 가진 AD Converter에 의해, 아날로그 전압값은(0v~5v) 디지털 값(0~1023)으로 변환되어,  아두이노 코드에서 'analogRead(A0)' 함수를 통해 변환된 데이터를 읽어서 처리할 수 있게 됩니다. 

서보모터 회로에서는 PWM 기능이 있는 포트를 서보모터의 제어선(노란색 데이터선)과 연결하게 되며, 
<Servo.h>라는 라이브러리를 사용하면 servo.write(각도) 형태로 모터의 회전 위치를 제어할 수 있게 되는 원리입니다.

▶ 회로 연결도 (조이스틱이 연결된 송신 회로 1번과,  서보모터 2개가 연결된 수신 회로 2번 두 가지를 만드세요)
《 회로1 :  조이스틱 Nano 회로 》

 조이스틱을 연결할 때는 아래 이미지처럼, 보통 '암-수' 형태의 점퍼 케이블로 연결하게 됩니다. 

하지만, 여기서는 좀 더 간결한 회로를 만들기 위해, 조이스틱의 있는 핀을 구부려서 브레드보드에 직접 연결하였는데요, 
작업 과정에서 핀이 부러지거나 손상될 수 있으니,  조이스틱의 여유 개수가 있는 분만 시도해 보시기 바랍니다. 
방법은 아래 이미지를 보세요, 조이스틱의 핀은,  아래 분홍색 박스의 이미지와 같은 핀헤더로 납땜되어 있습니다. 
그럼, 핀헤더를 고정하고 있는 플라스틱 부분을 니퍼로 사이사이를 잘라내면,  플라스틱 조각은 빠져나오게 되고,  핀의 길이가 구부려도 여유 있는 상태가 됩니다.   그럼, 브레드보드에 밀착시켜서 꽂을 수 있게 됩니다. 



《 회로 2 :  서보모터 Nano 회로 》

서보모터는 회로도처럼 그냥 2개를 연결시켜 놓기만 해도 되지만, 기왕이면, 아래 이미지와 같은 서보모터 틸트 거치대 같은 것을 활용해서 만들어 보면, 곧바로 응용해볼 수도 있고 해서 좋을 것 같네요. 
예를 들어 틸트 위에 소형 아두이노 카메라 모듈이나, ESP32-CAM과 같은 모듈을 부착해서 활용할 수 있겠네요.

그리고, 위 틸트 거치대의 노란색 화살표 부분을 보면, SG90 서보모터에 같이 동봉된 하얀색 핀과  틸트 거치대 홈의 길이가 딱 맞지 않기 때문에 하얀색 핀을 일부 잘라내어야 합니다. 

그리고, 서보모터 커넥터 핀의 기본 스타일은 암놈 형태의 핀으로 되어 있기 때문에,  브레드 보드에 서보모터 커넥터를 연결하려면, 아래 그림과 같은 핀헤더 연결핀이 필요할 수 있습니다. 

만약, 이미지와 같은 핀헤더가 없다면,  굵은 전선(전선 한 가닥으로 된 단선)을 잘라 꽂거나, 혹은  저항이나 LED와 같은 부품의 리드선(다리)을 잘라서 활용해도 됩니다. 

▶ 아두이노 코드 
( 아래의 코드를 각각의 회로에 업로드해주세요. )
《 실습 6 : 조이스틱 1번 회로 코드 》

// === HC-12 'Joystick' Control 회로 코드   ===
// RasINO IoT : https://rasino.tistory.com/326

#include <SoftwareSerial.h> 
SoftwareSerial HC12(2, 3); // HC-12 TX Pin, HC-12 RX Pin 
int Jox=0, Joy=0;

void setup() { 
  Serial.begin(9600); // Computer ↔ 시리얼포트(아두이노) 통신속도
  HC12.begin(9600);   // 시리얼포트(아두이노) ↔ HC12   통신속도
} 
void loop() { 
  // 시리얼모니터로 수신(입력)데이터가 있을 경우 HC12를 통해 데이터를 발송
  Jox = map(analogRead(A0),0,1023,0,180);
  Joy = map(analogRead(A1),0,1023,0,180);
  Serial.print(Jox);
  Serial.print("\t");
  Serial.println(Joy);
  // 아래 X 문자를 아스키 값으로 변환되지 않고 그대로 전송하기 위해 write( )함수 사용
  HC12.print(Jox); HC12.write("X"); // 조이스틱 X축 값을 보내고 이어 "X"문자를 전송  
  HC12.print(Joy); HC12.write("Y"); // 조이스틱 Y축 값을 보내고 이어 "Y"문자를 전송
  delay(50);   // 전송 시간 확보를 위한 딜레이   
}

《 위 코드 다운로드 》

HC12_LED_L3_Joy.zip
0.00MB


《 실습6 : 서보모터 2번 회로 코드 》

// ###  HC-12 '서보 x 2 연결 회로 코드'   ###
// RasINO IoT : https://rasino.tistory.com/326

#include <Servo.h>
#include <SoftwareSerial.h> 
SoftwareSerial HC12(2, 3); // HC-12 TX Pin, HC-12 RX Pin 
Servo servo1, servo2;
int servo1Pin=5;  // 1번 서보모터 연결된 아두이노 핀
int servo2Pin=9;  // 2번 서보모터 연결된 아두이노 핀
byte incomingByte;  // 0~255 값 저장할 수 있는 byte변수 선언
String readBuffer = "";
String readBufferX = "";
String readBufferY = "";
int Jox = 0;
int Joy = 0;
int i = 0;
bool x_ready = false;
bool y_ready = false;
bool x_passed = false;
bool data_received = false;

void setup() { 
  Serial.begin(9600); // computer ↔ 시리얼포트(아두이노) 통신속도
  HC12.begin(9600);   // 시리얼포트(아두이노) ↔ HC12   통신속도
  Serial.println("This is 'A-Servo Motor' HC-12 Module"); 
}  

void loop() { 
  while (HC12.available() > 0) { 
    incomingByte = HC12.read();   // 수신 데이터를 byte 단위로 저장
    readBuffer += char(incomingByte); // 수신되는 데이터를 문자형으로 캐스팅하여 문자열 변수(readBuffer)에 쌓아 둠
  }
  delay(70);  // 송신측 전송 delay(50) 타임보다 최소 같거나 더 높이 설정해 주어야 함.
// 송신측(코드)에서 X joy 값을 보내고 "X" 문자를 보낸 후 ,  Y joy값을 보내고 "Y"문자를 보낸 것을 기억하세요.
  while (i <= sizeof(readBuffer)) {
    if (readBuffer[i] == 'X') {
      x_ready = true;
    }
    if (readBuffer[i] == 'Y') {
      y_ready = true;
    }
    if (!x_ready) {
      readBufferX = readBufferX + (readBuffer[i]);
    }
    if (x_passed && !y_ready){
      readBufferY = readBufferY + (readBuffer[i]);
    }
    if (x_ready) {
      x_passed = true;
    }
    i = i+1;
  }
  data_received = true;  
  Jox = readBufferX.toInt();  //문자열로 저장된 X 데이터 값을 정수형으로 변환하여 저장.
  Joy = readBufferY.toInt();  //문자열로 저장된 Y 데이터 값을 정수형으로 변환하여 저장.
  if (data_received) {
    // 데이터 버퍼 변수 들을 리셋.
    readBuffer = "";  
    readBufferX = "";
    x_ready = false;
    x_passed = false;
    readBufferY = "";
    y_ready = false;
    i=0;
  }
  data_received =false;
  servo1.attach (servo1Pin);
  servo2.attach (servo2Pin);  
  servo1.write(Jox);      
  servo2.write(Joy);      
  delay(26); 
  servo1.detach();
  servo2.detach();
  delay(15);   
  Serial.print(Jox);
  Serial.print("\t");
  Serial.println(Joy); 
}

《 위 코드 다운로드 》

HC12_LED_A_Servo.zip
0.00MB


▶ 동작 실행(방법)
 :  전원을 연결하면,  예를 들어 조이스틱을 상하로 움직이면, 1번 서보모터가 상하로 움직이며,   조이스틱을 좌우로 움직이면, 2번 서보모터가 좌우로 움직이게 됩니다. 
그런데, 제가 올린 영상에 보면, 기본적인 서보모터 제어 코드로 제어하게 되면, 대부분의 경우 서보모터 떨림 현상을 겪게 됩니다.   그렇다고 제어가 안 되는 것은 아니고, 제어되기는 하지만, 조이스틱을 움직이지 않을 때는 더욱 심하게 상하 좌우로 떨게 되어, 작품의 완성도가 상당히 떨어지게 됩니다. 
원인은 몇 가지가 있을 수 있겠지만,  지난번에 올린 서보모터 떨림 개선이라는 게시글을 참고해보세요.  떨림 원인과 개선에 대한 자세한 설명되어 있습니다.  (자료 링크 : 
【 아두이노에러해결#4】 서보모터 떨림, 불안정 현상 해결! )
아무튼 본 게시글의 아두이노 코드에는 attach( )함수와, detatch( )함수를 사용한 개선된 코드로 올려져 있으니 떨림이 거의 없게 동작할 거예요.   그럼에도 모터의 떨림이 생길 수 있는데요, 이럴 때는 아래에 표시된 delay( ) 함수의 시간 값을 조금씩 앞뒤로 조절해 보세요. 

 

그리고 당연한 이야기지만, PC 연결에 의존하지 않고, 보조배터리(5V) 연결로도 무선통신이 되며, 잘 작동이 됩니다. 

 

그럼, 끝으로 HC-12 모듈의 주요 장점을 정리해 드리며, 마치도록 하겠습니다. 
본 게시글 끝에 있는 HC-12 모듈에 대한 풀코스 학습 영상과 꼭 같이 보면서 실습을 한다면, 실습을 진행하는데 별 어려움 없이 완료할 수 있을 것으로 생각됩니다. 
감사합니다~ 
그럼, 오늘도 좋은 하루 보내세요~  &^^ 

 

【 HC-12 모듈 풀 코스 학습 영상 】

 아래 영상을 클릭해보세요.

 

 

반응형