이 아두이노 튜토리얼에서는 HC-12 무선 시리얼 통신 모듈을 사용하여 여러 아두이노 보드 간에 최대 1.8km 거리까지 장거리 무선 통신을 구현하는 방법을 배웁니다. 아래 비디오를 시청하거나 작성된 튜토리얼을 읽어보세요.
개요
이 튜토리얼에서는 HC-12 모듈 연결과 두 아두이노 간의 기본 통신, 그리고 가속도계 센서를 이용해 첫 번째 아두이노에서 두 번째 아두이노의 스테퍼 모터 위치를 무선으로 제어하는 추가 예제까지 총 세 가지 예제를 다룹니다.
HC-12 무선 통신 모듈
먼저 HC-12 무선 시리얼 포트 통신 모듈을 자세히 살펴보겠습니다. 주요 사양은 다음과 같습니다.
무선 작동 주파수 대역: 433.4MHz ~ 473.0MHz
총 100개 채널, 채널 간 간격 400kHz
송신 전력: -1dBm(0.79mW) ~ 20dBm(100mW)
수신 감도: -117dBm(0.019pW) ~ -100dBm(10pW)
이 수치들은 선택한 시리얼 및 공중(Over-the-Air) 보드레이트에 따라 달라지며, 아래 표를 참조하세요.
HC-12 모듈은 사용자가 프로그래밍할 필요 없는 내장 마이크로컨트롤러를 가지고 있습니다. 모듈 설정은 아두이노, PC 또는 기타 마이크로컨트롤러의 시리얼 포트를 통해 AT 명령어로 수행합니다. AT 명령 모드에 진입하려면 모듈의 "Set" 핀을 로우(Low) 논리 레벨로 설정하면 됩니다.
아두이노와 HC-12
이제 HC-12 모듈을 아두이노에 연결하고 첫 번째 예제를 진행해 보겠습니다. 회로도는 다음과 같습니다. 모듈 작동 전압은 3.2V ~ 5.5V이며, 안정적인 작동을 위해 디커플링 커패시터와 외부 전원 공급 장치 사용을 권장합니다. 다만 이 튜토리얼의 세 가지 예제 모두 PC USB 전원만으로도 문제없이 작동했습니다.
첫 번째 모듈은 아두이노 우노(UNO)에, 두 번째 모듈은 아두이노 메가(MEGA)에 연결했지만, 원하는 보드를 사용해도 무방합니다.
이 튜토리얼에 필요한 부품은 아래 링크에서 구할 수 있습니다:
HC-12 무선 통신 모듈 ………..
아두이노 보드 ………………………………………………
브레드보드와 점퍼 와이어 …………………………
예제 01 – 아두이노 코드
시리얼 모니터를 이용한 두 모듈 간 기본 통신을 위한 아두이노 코드입니다.
/* 아두이노 장거리 무선 통신 HC-12 예제 01 by Dejan Nedelkovski, www.HowToMechatronics.com */
#include <SoftwareSerial.h>
SoftwareSerial HC12(10, 11); // HC-12 TX 핀, HC-12 RX 핀
void setup() {
Serial.begin(9600); // 컴퓨터용 시리얼 포트
HC12.begin(9600); // HC12용 시리얼 포트
}
void loop() {
while (HC12.available()) { // HC-12에 데이터가 있으면
Serial.write(HC12.read()); // 시리얼 모니터로 데이터 전송
}
while (Serial.available()) { // 시리얼 모니터에 데이터가 있으면
HC12.write(Serial.read()); // 해당 데이터를 HC-12로 전송
}
}코드 언어: Arduino (arduino)
두 아두이노 모두 동일한 코드를 사용합니다. 두 아두이노를 별도의 컴퓨터에 연결하거나 단일 컴퓨터에 연결해도 됩니다.
단일 컴퓨터를 사용하는 경우, 첫 번째 아두이노를 연결하고 보드 모델과 COM 포트를 선택해 코드를 업로드한 후, 두 번째 아두이노를 연결하고 아두이노 IDE를 다시 실행해 다른 COM 포트를 선택한 뒤 같은 코드를 업로드하면 됩니다.
두 IDE가 모두 실행되면 시리얼 모니터를 열고 통신 테스트를 할 수 있습니다. 한 쪽 시리얼 모니터에 입력한 내용이 다른 쪽 아두이노로 전송됩니다.
코드 동작 원리: 시리얼 모니터에서 문자을 입력하고 전송 버튼을 누르면, 첫 번째 아두이노의 Serial.available() 조건이 참이 되어 HC12.write()로 데이터를 HC-12 모듈에 보냅니다. 이 모듈은 데이터를 무선으로 두 번째 HC-12 모듈에 전송하고, 두 번째 아두이노에서는 HC12.available()이 참이 되어 Serial.write()로 시리얼 모니터에 데이터를 출력합니다.
같은 코드로 AT 명령어를 보내 모듈 파라미터를 설정할 수도 있습니다. 모듈의 "Set" 핀을 그라운드(GND) 또는 아두이노 디지털 핀에 연결하고 로우 레벨로 설정하기만 하면 됩니다.
시리얼 모니터에 "AT"를 입력해 "OK" 응답이 오는지 확인하면 AT 명령 모드 진입 여부를 알 수 있습니다. 총 12개의 AT 명령어가 있으며, 보드레이트, 채널, 송신 전력 등 다양한 파라미터 변경에 사용됩니다. 예를 들어 "AT+B38400"을 보내면 모듈 보드레이트가 38400으로 설정됩니다.
AT 명령어:
1. AT – 테스트 명령어.
예: "AT" 전송 → 모듈에서 "OK" 반환.
2. AT+Bxxxx – 시리얼 포트 보드레이트 변경.
사용 가능 보드레이트: 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200 bps. 기본값: 9600 bps.
예: "AT+B38400" 전송 → "OK+B19200" 반환.
3. AT+Cxxxx – 무선 통신 채널 변경 (001~100).
기본값: 채널 001 (작동 주파수 433.4MHz). 채널당 400kHz 증가.
예: 채널 006으로 설정하려면 "AT+C006" 전송 → "OK+C006" 반환. 새 주파수: 435.4MHz.
예제 02
이번 예제에서는 두 개의 푸시 버튼으로 통신 채널을 선택하고, 수신 데이터를 저장하는 다른 방법을 살펴봅니다.
참고: 두 HC-12 모듈의 "Set" 핀은 각 아두이노의 6번 핀에, 첫 번째 아두이노의 두 버튼은 4번과 3번 핀에 연결됩니다.
첫 번째 아두이노 코드:
/* 아두이노 장거리 무선 통신 HC-12 예제 02 - 푸시 버튼으로 채널 변경 - 버튼 측 by Dejan Nedelkovski, www.HowToMechatronics.com */
#include <SoftwareSerial.h>
#define setPin 6
#define button1 4
#define button2 3
SoftwareSerial HC12(10, 11); // HC-12 TX 핀, HC-12 RX 핀
byte incomingByte;
String readBuffer = "";
int button1State = 0;
int button1Pressed = 0;
int button2State = 0;
int button2Pressed = 0;
void setup() {
Serial.begin(9600);
HC12.begin(9600);
pinMode(setPin, OUTPUT);
pinMode(button1, INPUT);
pinMode(button2, INPUT);
digitalWrite(setPin, HIGH); // HC-12 일반 투명 모드
}
void loop() {
// ==== 수신 데이터를 문자열 변수에 저장
while (HC12.available()) {
incomingByte = HC12.read();
readBuffer += char(incomingByte);
}
delay(100);
// ==== 시리얼 모니터를 통해 한 HC-12에서 다른 HC-12로 데이터 전송
while (Serial.available()) {
HC12.write(Serial.read());
}
// ==== 버튼 1 눌림: 채널 01 설정
button1State = digitalRead(button1);
if (button1State == HIGH & button1Pressed == LOW) {
button1Pressed = HIGH;
delay(20);
}
if (button1Pressed == HIGH) {
HC12.print("AT+C001"); // 다른 모듈로 AT 명령 전송
delay(100);
digitalWrite(setPin, LOW); // HC-12 AT 명령 모드 진입
delay(100);
HC12.print("AT+C001"); // HC-12에 AT 명령 전송
delay(200);
while (HC12.available()) {
Serial.write(HC12.read()); // 응답을 시리얼 모니터로 출력
}
Serial.println("채널 변경 완료");
digitalWrite(setPin, HIGH); // AT 명령 모드 종료
button1Pressed = LOW;
}
// ==== 버튼 2 눌림: 채널 02 설정
button2State = digitalRead(button2);
if (button2State == HIGH & button2Pressed == LOW) {
button2Pressed = HIGH;
delay(100);
}
if (button2Pressed == HIGH) {
HC12.print("AT+C002");
delay(100);
digitalWrite(setPin, LOW);
delay(100);
HC12.print("AT+C002");
delay(200);
while (HC12.available()) {
Serial.write(HC12.read());
}
Serial.println("채널 변경 완료");
digitalWrite(setPin, HIGH);
button2Pressed = LOW;
}
checkATCommand();
readBuffer = "";
}
void checkATCommand() {
if (readBuffer.startsWith("AT")) {
digitalWrite(setPin, LOW);
delay(200);
HC12.print(readBuffer);
delay(200);
while (HC12.available()) {
Serial.write(HC12.read());
}
digitalWrite(setPin, HIGH);
}
}코드 언어: Arduino (arduino)
두 번째 아두이노 코드:
/* 아두이노 장거리 무선 통신 HC-12 예제 02 - 푸시 버튼으로 채널 변경 by Dejan Nedelkovski, www.HowToMechatronics.com */
#include <SoftwareSerial.h>
#define setPin 6
SoftwareSerial HC12(10, 11);
byte incomingByte;
String readBuffer = "";
void setup() {
Serial.begin(9600);
HC12.begin(9600);
pinMode(setPin, OUTPUT);
digitalWrite(setPin, HIGH);
}
void loop() {
while (HC12.available()) {
incomingByte = HC12.read();
readBuffer += char(incomingByte);
}
delay(100);
while (Serial.available()) {
HC12.write(Serial.read());
}
// === 버튼 1 눌림: 채널 01 설정
if (readBuffer == "AT+C001") {
digitalWrite(setPin, LOW);
delay(100);
HC12.print(readBuffer);
delay(200);
while (HC12.available()) {
Serial.write(HC12.read());
}
Serial.println("채널 변경 완료");
digitalWrite(setPin, HIGH);
readBuffer = "";
}
// === 버튼 2 눌림: 채널 02 설정
if (readBuffer == "AT+C002") {
digitalWrite(setPin, LOW);
delay(100);
HC12.print(readBuffer);
delay(200);
while (HC12.available()) {
Serial.write(HC12.read());
}
Serial.println("채널 변경 완료");
digitalWrite(setPin, HIGH);
readBuffer = "";
}
checkATCommand();
readBuffer = "";
}
void checkATCommand() {
if (readBuffer.startsWith("AT")) {
digitalWrite(setPin, LOW);
delay(100);
HC12.print(readBuffer);
delay(200);
while (HC12.available()) {
Serial.write(HC12.read());
}
digitalWrite(setPin, HIGH);
}
}코드 언어: Arduino (arduino)
코드 설명:
먼저 핀을 정의하고 "Set" 핀을 하이(High) 레벨로 설정해 모듈이 일반 투명 모드로 작동하게 합니다. 첫 번째 while 루프로 수신 데이터를 문자열 변수에 저장해 처리하기 쉽게 만듭니다.
// ==== 수신 데이터를 문자열 변수에 저장
while (HC12.available()) {
incomingByte = HC12.read();
readBuffer += char(incomingByte);
}코드 언어: Arduino (arduino)
수신 데이터는 한 바이트씩 들어오므로, 예를 들어 두 번째 아두이노에서 "Test123"을 보내면 이 루프는 7번 반복됩니다. 각 반복에서 HC12.read()로 바이트를 읽어 "readBuffer" 문자열 변수에 추가합니다.
첫 번째 푸시 버튼으로 통신 채널을 변경하는 방식을 살펴보겠습니다. 첫 번째 버튼을 누르면 HC12.print()로 "AT+C001" 문자열을 HC-12 모듈(또는 두 번째 아두이노)에 전송합니다.
if (button1Pressed == HIGH) {
HC12.print("AT+C001");
delay(100);
digitalWrite(setPin, LOW);
delay(100);
HC12.print("AT+C001");
delay(200);
while (HC12.available()) {
Serial.write(HC12.read());
}
Serial.println("채널 변경 완료");
digitalWrite(setPin, HIGH);
button1Pressed = LOW;
}코드 언어: Arduino (arduino)
이 문자열이 두 번째 아두이노에서 수신되면 HC-12 모듈을 AT 명령 모드로 설정하고 같은 문자열 "AT+C001"을 써서 모듈을 통신 채널 1로 설정합니다.
// 두 번째 아두이노에서
if (readBuffer == "AT+C001") {
digitalWrite(setPin, LOW);
delay(100);
HC12.print(readBuffer);
delay(200);
while (HC12.available()) {
Serial.write(HC12.read());
}
Serial.println("채널 변경 완료");
digitalWrite(setPin, HIGH);
readBuffer = "";
}코드 언어: Arduino (arduino)
다음 while 루프로 HC-12 모듈의 응답 메시지를 출력해 채널 변경 성공 여부를 확인합니다.
while (HC12.available()) {
Serial.write(HC12.read());
}코드 언어: Arduino (arduino)
첫 번째 아두이노에서도 동일한 절차로 첫 번째 HC-12 모듈에 AT 명령어를 보냅니다. 두 번째 버튼을 눌러 채널 2로 설정하는 방식도 같습니다. 이 방법을 사용하면 언제든 통신할 HC-12 모듈을 선택할 수 있습니다.
마지막으로 checkATCommand() 사용자 정의 함수는 수신된 메시지가 "AT"로 시작하는지 확인해 AT 명령어라면 모듈을 AT 명령 모드로 진입시키고 명령을 실행합니다.