스마트 디바이스 5주차 블루투스 - yubiine/25-1_smartdevice GitHub Wiki

⭐목표

  • 블루투스 통신의 기본 개념을 이해한다.
  • ESP32의 클래식 블루투스 및 BLE 방식을 활용하여 데이터를 송수신한다.
  • BLE를 이용하여 RGB LED를 제어하는 실습을 진행한다.

📌무선통신이란?

전선(케이블) 없이 전파(RF), 적외선(IR), 빛 등을 이용해 정보(데이터)를 주고받는 통신 방식 (전자기파 사용)

🔹 1. 전파(Radio Wave)

  • 무선통신은 **전파(전자기파)**를 사용
  • 전파는 공기 중을 통해 에너지와 신호를 전달

🔹 2. 주파수(Frequency)

  • 전파는 파형으로 전달되고, **1초당 진동 수(Hz)**로 표현
  • 주파수 대역에 따라 용도가 나뉨
주파수 대역 예시 특징
13.56 MHz NFC 매우 근거리, 낮은 속도, 높은 보안성
2.4 GHz Bluetooth, Zigbee, Wi-Fi 비교적 넓은 커버리지, 간섭 가능성 ↑
5 GHz Wi-Fi 높은 속도, 짧은 거리
3~10 GHz UWB 초정밀 위치인식 가능

주파수가 높을수록 데이터 전송 속도 ↑, 거리 ↓
주파수가 낮을수록 통신거리 ↑, 데이터 속도 ↓


🔹 3. 송신기 / 수신기

  • 송신기: 데이터를 무선 신호로 변환해 보냄
  • 수신기: 신호를 받아서 원래의 데이터로 변환함

🔹 채널 (Channel)

의미: 주파수 대역 내에서 데이터 전송을 위해 사용되는 세부 주파수 영역

예시:

  • Bluetooth: 2.4 GHz 대역에서 1 MHz 폭의 79개 채널 사용 (Classic)
  • Wi-Fi: 2.4 GHz 대역에서 20 MHz 폭의 13~14개 채널
  • NFC: 채널 구분 없음, 단일 주파수 사용

✅ 채널 분할 이유: 여러 사용자가 같은 주파수 대역을 동시에 사용할 수 있도록 하기 위해

✅ 간섭: 여러 기기가 같은 주파수 대역에서 통신할 때 신호 충돌이 발생하는 현상
→ 데이터 손실, 연결 불안정 발생
주파수 호핑 (Frequency Hopping Spread Spectrum, FHSS)기술 사용
원리: 짧은 시간 간격으로 통신 주파수를 랜덤하게 변경하며 데이터 송수신

특징 내용
장점 간섭에 강함, 도청·해킹 방지
방식 Bluetooth Classic: 1600회/초 주파수 변경
BLE Low Energy에서는 Adaptive Frequency Hopping (AFH) 사용 → 혼잡 채널 회피

📌블루투스란?

근거리 무선 통신 기술로, 2.4GHz 주파수를 사용해 여러 기기를 무선으로 연결하는 기술

항목 블루투스 클래식 BLE (Bluetooth Low Energy)
주 용도 음악, 통화, 파일 전송 등 대용량, 지속적 데이터 통신 센서, IoT, 스마트워치 등 저전력 통신
속도 최대 3 Mbps 약 1 Mbps
전력 소모 높음 (지속 연결 필요) 매우 낮음 (필요할 때만 통신)
연결 방식 지속적 연결 (스트리밍 중심) 광고(advertising) & 필요 시 연결
멀티 디바이스 연결 수 적음 다수 연결 가능 (센서 네트워크 적합)
대표 예시 무선 이어폰, 블루투스 스피커, 차량 핸즈프리 스마트워치, 심박 센서, 스마트 전구, 온도 센서.

✅ Bluetooth Classic

  • 주파수 대역: 2.402 GHz ~ 2.480 GHz
  • 채널: 1 MHz 폭, 79개 채널
  • 호핑 속도: 초당 1600회

✅ Bluetooth Low Energy (BLE)

  • 주파수 대역: 2.402 GHz ~ 2.480 GHz
  • 채널: 2 MHz 폭, 40개 채널
  • 37개 데이터 채널 + 3개 광고 채널
  • Adaptive Frequency Hopping 사용:
  • 사용 중인 환경에서 혼잡한 채널을 피하고, 안정적인 채널만 사용

📌결과

무선통신 품질 = 주파수 대역 + 채널 활용 + 간섭 방지 기술 조합

요소 역할
주파수 속도와 커버리지 결정
채널 여러 사용자 간의 구분
주파수 호핑 간섭 회피, 보안성 향상
채널 선택 혼잡 회피, 데이터 효율 ↑

📌실습

아날로그 출력 실습 (PWM)

image

  • 처음에 위와 같이 글자가 깨지는 오류 발생
  • Baud rate 설정 (9600)
#include "BluetoothSerial.h"

String device_name = "ESP32_DEVICE";

// Check if Bluetooth is available
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif

// Check Serial Port Profile
#if !defined(CONFIG_BT_SPP_ENABLED)
#error Serial Port Profile for Bluetooth is not available or not enabled. It is only available for the ESP32 chip.
#endif


BluetoothSerial SerialBT;

void setup() {
  Serial.begin(9600);
  SerialBT.begin(device_name);
  SerialBT.deleteAllBondedDevices();
  Serial.printf("The device with name \"%s\" is started.\nNow you can pair it with Bluetooth!\n", device_name.c_str());
}

void loop() {
  if (Serial.available()) {
    SerialBT.write(Serial.read());
  }
  if (SerialBT.available()) {
    Serial.write(SerialBT.read());
  }
  delay(20);
}

IMG_6231.2.MOV
#include "BluetoothSerial.h"

String device_name = "ESP32_DEVICE";

const int ledPin = 2; // LED가 연결된 핀 번호

BluetoothSerial SerialBT;

void setup() {
  Serial.begin(9600);
  SerialBT.begin(device_name);  //Bluetooth device name
  Serial.printf("The device with name \"%s\" is started.\nNow you can pair it with Bluetooth!\n", device_name.c_str());
  pinMode(ledPin, OUTPUT); // LED 핀을 출력으로 설정
  digitalWrite(ledPin, LOW); // 초기 상태를 OFF로 설정

}

void loop()
{
  if (SerialBT.available())
  {
    char incoming = SerialBT.read();
    Serial.write(incoming); // 수신된 데이터를 시리얼 모니터에 출력

    if (incoming == '1')
    {
      digitalWrite(ledPin, HIGH); // '1'을 수신하면 LED ON
      Serial.println("LED ON");
    }
    else if (incoming == '0')
    {
      digitalWrite(ledPin, LOW); // '0'을 수신하면 LED OFF
      Serial.println("LED OFF");
    }
  }
}
IMG_6232.2.MOV
#include "BluetoothSerial.h"

String device_name = "ESP32_DEVICE";

const int RED_PIN = 4; 
const int GREEN_PIN = 15; 
const int BLUE_PIN = 2; 
BluetoothSerial SerialBT;

void setup() {
  Serial.begin(9600);
  SerialBT.begin(device_name);  //Bluetooth device name
  Serial.printf("The device with name \"%s\" is started.\nNow you can pair it with Bluetooth!\n", device_name.c_str());
  pinMode(RED_PIN, OUTPUT); // LED 핀을 출력으로 설정
  pinMode(GREEN_PIN, OUTPUT); 
  pinMode(BLUE_PIN, OUTPUT); 

  digitalWrite(RED_PIN, HIGH); // 초기 상태를 OFF로 설정
  digitalWrite(GREEN_PIN, HIGH); 
  digitalWrite(BLUE_PIN, HIGH); 

}

void loop() {
  // 빨강
  
  analogWrite(RED_PIN, 0);
  analogWrite(GREEN_PIN, 255);
  analogWrite(BLUE_PIN, 255);
  delay(1000);

  // 초록
  analogWrite(RED_PIN, 255);
  analogWrite(GREEN_PIN, 0);
  analogWrite(BLUE_PIN, 255);
  delay(1000);

  // 파랑
  analogWrite(RED_PIN, 255);
  analogWrite(GREEN_PIN, 255);
  analogWrite(BLUE_PIN, 0);
  delay(1000);

  // 백색
  analogWrite(RED_PIN, 0);
  analogWrite(GREEN_PIN, 0);
  analogWrite(BLUE_PIN, 0);
  delay(1000);

  // 끄기
  analogWrite(RED_PIN, 255);
  analogWrite(GREEN_PIN, 255);
  analogWrite(BLUE_PIN, 255);
  delay(1000);
}
IMG_6234.2.MOV
//라이브러리를 가져옵니다.
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
//서비스와 특성에 대한 UUID를 정의합니다.
#define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define RGB_CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
#define NOTYFY_CHARACTERISTIC_UUID "d501d731-f0f9-4121-a7f6-2c0f959f1583"
//RGB LED에 사용될 핀 번호를 정의합니다
#define RED_PIN   4
#define GREEN_PIN 15
#define BLUE_PIN  2
//BLE 관련 객체를 선언합니다.
BLEServer *pServer; //BLE 서버 객체
BLEService *pService; // BLE 서비스 객체
BLECharacteristic *pRGBCharacteristic = NULL; //BLE 특성 객체
BLECharacteristic* pCharacteristic = NULL; //BLE 특성 객체
//RGB 값을 저장할 변수들을 초기화합니
int redValue = 0;
int greenValue = 0;
int blueValue = 0;
//BLE 특성에 대한 콜백 클래스를 정의합니다.
class MyCallbacks : public BLECharacteristicCallbacks {
  //특성의 값을 읽어와 RGB 값을 파싱하고 LED를 제어합니다.
  void onWrite(BLECharacteristic *pCharacteristic) {
    String value = pCharacteristic->getValue().c_str(); //특성의 값을 문자열로 읽어옵니다.

    // 값이 유효한 경우에만 처리
    if (value.length() > 0) {
      // RGB 값을 파싱하여 각각의 변수에 저장
      int delimiterPos1 = value.indexOf(',');
      int delimiterPos2 = value.lastIndexOf(',');

      if (delimiterPos1 != -1 && delimiterPos2 != -1 \
             && delimiterPos2 < value.length() - 1) {
        redValue = value.substring(0, delimiterPos1).toInt();
        greenValue = value.substring(delimiterPos1 + 1, delimiterPos2).toInt();
        blueValue = value.substring(delimiterPos2 + 1).toInt();

        // RGB 값을 LED의 밝기로 변환하여 제어합니다.
        analogWrite(RED_PIN, 255 - redValue);
        analogWrite(GREEN_PIN, 255 - greenValue);
        analogWrite(BLUE_PIN, 255 - blueValue);
      }
    }
  }
};

void setup() {
  // BLE 초기화하고 이름을 "RGB LED Control"로 설정합니다
  BLEDevice::init("LDevRGB");
  pServer = BLEDevice::createServer();
  pService = pServer->createService(SERVICE_UUID);
  
  // RGB 특성 생성 및 설정
  pRGBCharacteristic = pService->createCharacteristic(
    RGB_CHARACTERISTIC_UUID,
    BLECharacteristic::PROPERTY_WRITE
  );  
  pRGBCharacteristic->setCallbacks(new MyCallbacks());

  // Notify/Indicate 특성 생성 및 설정
  pCharacteristic = pService->createCharacteristic(
                      NOTYFY_CHARACTERISTIC_UUID,
                      BLECharacteristic::PROPERTY_NOTIFY |
                      BLECharacteristic::PROPERTY_INDICATE
                    );
    // Create a BLE Descriptor
  pCharacteristic->addDescriptor(new BLE2902());

  // 서비스를 서버에 추가
  pService->start();

  // BLE 광고 시작
  BLEAdvertising *pAdvertising = pServer->getAdvertising();
  pAdvertising->start();

    // 모든 핀을 HIGH로 설정하여 LED를 꺼진 상태로 초기화합니다.
  digitalWrite(RED_PIN, HIGH);
  digitalWrite(GREEN_PIN, HIGH);
  digitalWrite(BLUE_PIN, HIGH);
}

void loop() {
  // RGB 값을 16진수 형태로 변환하여 Notify
  char hexValue[8]; 
  sprintf(hexValue, "#%02X%02X%02X", redValue, greenValue, blueValue);
  //Notify 특성의 값을 hexValue로 설정합니다.
  pCharacteristic->setValue(hexValue); 
  pCharacteristic->notify(); //Notify를 통해 값을 전달합니다.

  delay(100);  // 알림 간격을 조절할 수 있습니다.
}
IMG_6235.2.MOV
IMG_6236.2.MOV
IMG_6237.2.MOV
⚠️ **GitHub.com Fallback** ⚠️