통신 실험실 #3: ESP32 Wi-Fi 가이드

기운찬곰·2025년 9월 25일

통신 실험실

목록 보기
3/3
post-thumbnail

Wi-Fi 란?

Wi-Fi는 IEEE 802.11 표준에 기반하여 만들어진 무선 근거리 통신망(WLAN) 기술의 상표명입니다. 쉽게 말해, 케이블 없이 전파를 이용해 데이터를 주고받아 인터넷에 연결하는 기술을 통칭합니다.

Wi-Fi의 기본 원리 및 구성 요소

Wi-Fi는 유선 인터넷(LAN)을 무선으로 확장하는 방식으로 작동합니다.

  • 주요 작동 원리: 유선 인터넷 신호가 무선 공유기(라우터)나 액세스 포인트(AP)로 들어오면, 이 장치가 해당 신호를 전파(Radio waves) 형태로 변환하여 주변으로 송출합니다.
  • 데이터 전송: 이 전파에는 컴퓨터 데이터가 이진 코드(0과 1)로 인코딩되어 실려 있으며, 스마트폰, 노트북, ESP32 같은 장치들이 이 전파를 수신하고 다시 데이터로 복원하여 인터넷을 사용합니다.

주요 구성 요소로는 다음과 같습니다.

  • 액세스 포인트 (AP): Wi-Fi 신호를 생성하고 관리하는 장치 (일반적으로 '무선 공유기'라고 부름).
  • 스테이션 (STA): AP에 연결하여 서비스를 이용하는 클라이언트 장치 (스마트폰, 노트북, ESP32 등).

초기 역사

1985년: FCC의 ISM 대역 개방

Wi-Fi 기술의 기반은 1985년 미국 연방통신위원회(FCC)가 2.4GHz ISM(Industrial, Scientific, Medical) 대역을 라이선스 없이 사용할 수 있도록 개방하면서 무선 데이터 통신의 기반이 마련되었습니다.

1997년: IEEE 802.11 표준 제정

최초의 Wi-Fi 표준인 IEEE 802.11이 발표되어 2.4GHz 대역에서 최대 2Mbps 속도로 무선 데이터 전송이 가능해졌으며, 이것이 현대 Wi-Fi의 출발점이 되었습니다.

1999년: Wi-Fi 얼라이언스 설립과 브랜딩

무선 기기 제조업체들이 모여 Wi-Fi Alliance를 설립하고 "Wi-Fi"라는 브랜드명을 만들었으며, 서로 다른 제조사 기기 간의 호환성을 보장하는 인증 프로그램을 시작했습니다.

1999년: 802.11b 등장으로 대중화

11Mbps 속도를 지원하는 802.11b 표준이 발표되면서 실용적인 속도를 확보했고, 애플의 iBook과 AirPort 베이스 스테이션 출시로 일반 소비자들에게 Wi-Fi가 본격 보급되기 시작했습니다. 이 제품은 와이파이 네트워크 연결을 제공하는 최초의 대량 소비자 제품이었습니다.

2000년대 초: 폭발적 성장

노트북 내장 Wi-Fi, 공항/카페의 핫스팟 서비스, 가정용 무선 라우터의 대중화가 이루어지면서 Wi-Fi는 현재와 같은 필수 인프라로 자리잡게 되었습니다. (그랬던가...? 음)

버전 별 특징

위키피디아 참고: https://en.wikipedia.org/wiki/Wi-Fi
+) 나무위키: https://namu.wiki/w/Wi-Fi (깔끔하네... 꽤 정확한거 같고)

802.11 (1997): 최초의 Wi-Fi 표준으로 2.4GHz에서 최대 2Mbps 속도를 제공했지만 실용성이 떨어져 거의 사용되지 않았습니다.

802.11b (1999): 2.4GHz에서 11Mbps를 제공하며 전파 도달 거리가 길고 저렴해서 Wi-Fi 대중화의 시발점이 된 실질적인 첫 번째 성공작입니다.

802.11a (1999): 5GHz 대역을 사용하여 최대 54Mbps를 달성했지만 높은 주파수로 인해 전파 도달 거리가 짧고 가격이 비싸서 널리 보급되지 못했습니다.

802.11g (2003): 2.4GHz의 장거리 특성과 5GHz의 고속 전송(54Mbps)을 결합하여 802.11b와 하위 호환성을 유지하면서 성능을 크게 향상시켰습니다.

802.11n/Wi-Fi 4 (2009): MIMO(다중 안테나) 기술을 도입하여 2.4GHz/5GHz 듀얼밴드에서 최대 600Mbps를 달성하고 전파 도달 범위도 크게 개선했습니다.

802.11ac/Wi-Fi 5 (2013): 기가비트(Gbps) 속도 달성. 5GHz 전용으로 MU-MIMO와 빔포밍 기술을 추가하여 최대 6.9Gbps의 초고속 전송과 다중 기기 동시 통신 효율성을 제공했습니다.

802.11ax/Wi-Fi 6 (2019): OFDMA 기술로 네트워크 효율성을 4배 향상시키고 최대 9.6Gbps 속도와 함께 IoT 기기 밀집 환경에서의 성능을 대폭 개선했습니다.

Wi-Fi 6E (2020): Wi-Fi 6 기술에 6GHz 대역을 추가하여 더 넓은 채널과 적은 간섭으로 초저지연과 안정적인 고속 통신을 가능하게 했습니다.

802.11be/Wi-Fi 7 (2024): MLO (멀티 링크 작동), 320 MHz 대역폭, 초저지연, 4K QAM 기술로 극한의 처리량을 달성했습니다.


참고. bps(bits per second)

초당 전송되는 비트 수를 나타내는 가장 기본적인 데이터 전송 속도 단위로, 디지털 통신에서 얼마나 빠르게 0과 1의 정보를 전송할 수 있는지를 측정합니다.

다양한 크기 단위로 확장됩니다: Kbps(천 비트/초), Mbps(백만 비트/초), Gbps(십억 비트/초) 등으로 사용되며, 예를 들어 56Kbps 모뎀은 초당 56,000비트를 전송할 수 있습니다.

저장 용량 단위인 Byte와 구분해야 합니다. 1Byte는 8bits이므로, 8Mbps 인터넷 속도는 실제로 1MB/s(초당 1메가바이트) 파일 다운로드 속도에 해당합니다. 100Mbps 인터넷으로 100MB 파일을 다운로드하려면 이론상 8초가 걸립니다(100MB × 8 = 800Mb, 800Mb ÷ 100Mbps = 8초).

실제 체감 속도는 이론값보다 낮습니다. 네트워크 오버헤드, 프로토콜 처리, 서버 응답 시간 등으로 인해 보통 이론 속도의 70-80% 정도가 실제 전송 속도이며, Wi-Fi는 거리나 장애물에 따라 더욱 감소할 수 있습니다.


버전별 핵심 변화를 정리하자면 다음과 같습니다.

  • 속도와 대역폭 증가: 세대가 바뀔수록 최대 데이터 전송 속도(Mbps→Gbps)가 극적으로 빨라졌고, 사용할 수 있는 채널 폭(20MHz→320MHz)도 넓어졌습니다.
  • MIMO/MU-MIMO: 802.11n(Wi-Fi 4)에서 MIMO(다중 안테나)를 도입하여 속도를 높였고, 802.11ac(Wi-Fi 5)에서는 MU-MIMO(다중 사용자)를 도입해 여러 장치에 동시 전송 효율을 높였습니다.
  • 주파수 확장: 초기 2.4GHz에서 시작하여 5GHz를 추가로 사용하게 되었고, Wi-Fi 6E 및 Wi-Fi 7에서는 더 넓은 비인가 대역인 6GHz까지 활용하고 있습니다.
  • 효율성/저지연성: Wi-Fi 6(802.11ax)에서 OFDMA를 도입하여 혼잡 환경에서 효율을 높였으며, Wi-Fi 7(802.11be)은 MLO(Multi-Link Operation) 등을 통해 초저지연 통신을 목표로 발전하고 있습니다.

동작 원리

  1. 네트워크 발견 및 인증: 기기가 주변 Wi-Fi 신호를 스캔하여 사용 가능한 네트워크(SSID) 목록을 확인하고, 사용자가 선택한 네트워크에 비밀번호를 입력하여 인증 과정을 거칩니다.

  2. 연결 및 IP 주소 할당: 인증이 완료되면 액세스 포인트(AP)와 연결이 설정되고, DHCP 프로토콜을 통해 기기에 고유한 IP 주소와 네트워크 설정 정보가 자동으로 할당됩니다.

  3. 데이터 패킷화 및 변조: 전송할 데이터(웹페이지, 이메일 등)를 작은 패킷 단위로 나누고 각각에 헤더 정보를 추가한 후, 디지털 신호를 2.4GHz/5GHz 전파에 변조하여 무선으로 전송합니다.

  4. 충돌 회피 및 전송: CSMA/CA 방식으로 다른 기기의 전송을 감지하고 채널이 비어있을 때 데이터를 전송하며, 수신측에서는 ACK 신호로 정상 수신을 확인합니다.

  5. 패킷 재조립 및 데이터 복원: 수신된 패킷들의 순서를 확인하고 오류를 검사한 후 원래 데이터로 재조립하여 최종적으로 애플리케이션(브라우저, 앱 등)에 전달합니다.

주요 기술

🎯 CSMA/CA(Carrier Sense Multiple Access with Collision Avoidance)

CSMA/CA는 충돌 회피 방식의 무선 매체 접근 제어 프로토콜로, 여러 기기가 같은 무선 채널을 공유할 때 동시 전송으로 인한 데이터 충돌을 미리 방지하는 기술입니다.

데이터를 전송하기 전에 채널이 비어있는지 감지(Carrier Sense)하고, 다른 기기가 사용 중이면 랜덤한 시간만큼 대기한 후(Backoff) 다시 시도하여 충돌 확률을 줄입니다.

유선 이더넷의 CSMA/CD와 달리 무선에서는 충돌 감지가 어려우므로 충돌을 미리 회피(Avoidance)하는 방식을 사용하며, RTS/CTS 핸드셰이크와 ACK 확인 메커니즘으로 안정적인 전송을 보장합니다

이미지 참고: http://www.ktword.co.kr/test/view/view.php?m_temp1=2038

🎯 MIMO(Multiple Input Multiple Output)

송신단과 수신단에 여러 개의 안테나를 사용하는 기술로, 같은 주파수 대역에서 여러 개의 독립적인 데이터 스트림을 동시에 전송하여 전송 속도를 배수로 증가시킬 수 있습니다.

공간 다중화(Spatial Multiplexing) 원리를 이용하여 각 안테나가 서로 다른 경로로 신호를 보내고, 수신측에서는 신호 처리 알고리즘으로 이들을 분리하여 원래 데이터를 복원합니다.

2×2 MIMO는 이론상 2배, 4×4 MIMO는 4배의 속도 향상이 가능하며, 추가로 다중 경로 페이딩에 대한 내성도 향상되어 신호 품질과 안정성도 개선됩니다.

이미지 참고: https://en.wikipedia.org/wiki/MIMO

🎯 OFDMA(Orthogonal Frequency Division Multiple Access)

직교 주파수 분할 다중 접속(OFDMA)은 널리 사용되는 직교 주파수 분할 다중화(OFDM) 디지털 변조 방식의 다중 사용자 접근 기술입니다. 하나의 넓은 채널을 여러 개의 작은 서브캐리어로 나눈 후, 이 서브캐리어들을 여러 사용자에게 동시에 할당하여 한 번에 다수의 기기가 통신할 수 있게 합니다.

기존에는 한 번에 하나의 기기만 전체 채널을 사용했지만, OFDMA는 채널을 작은 단위(Resource Unit)로 나누어 여러 기기가 동시에 각자의 할당된 부분을 사용할 수 있어 네트워크 효율성이 크게 향상됩니다.

Wi-Fi 6(802.11ax)에서 도입된 핵심 기술로, 특히 IoT 기기가 많은 환경에서 대기 시간을 줄이고 전체 네트워크 처리량을 4배까지 개선할 수 있어 밀집된 무선 환경의 성능을 혁신적으로 향상시켰습니다.

OFDM (OFDMA) 원리 및 특징 장단점 참고: https://ttistoryy.tistory.com/15

보안 업데이트

WEP(Wired Equivalent Privacy, 1997): 최초의 Wi-Fi 보안 표준으로 64비트/128비트 암호화를 사용했지만, 암호화 키가 쉽게 해독되는 치명적 취약점으로 인해 현재는 사용하지 않는 구식 보안 방식입니다.

WPA(Wi-Fi Protected Access, 2003): WEP의 취약점을 보완하기 위해 개발된 과도기적 보안 표준으로, TKIP(Temporal Key Integrity Protocol) 암호화와 동적 키 변경을 통해 보안을 강화했지만 여전히 일부 취약점이 존재합니다.

WPA2(2004): AES(Advanced Encryption Standard) 암호화를 도입하여 현재까지도 널리 사용되는 강력한 보안 표준이며, Personal(PSK) 모드와 Enterprise(802.1X) 모드를 제공하여 가정용과 기업용으로 구분해서 사용됩니다.

WPA3(2018): 최신 보안 표준으로 SAE(Simultaneous Authentication of Equals) 방식을 도입하여 브루트 포스 공격에 대한 내성을 크게 향상시켰고, 개별 기기별 암호화와 공개 Wi-Fi에서의 향상된 보안을 제공합니다.

💻 참고: https://en.wikipedia.org/wiki/Wi-Fi_Protected_Access

블루투스와의 차이점

  1. 용도와 범위: Wi-Fi는 인터넷 연결과 고속 데이터 전송을 위한 기술로 최대 100m 이상의 넓은 범위를 커버하는 반면, Bluetooth는 근거리 기기 간 연결(10m 이내)을 위한 개인 영역 네트워크(PAN) 기술입니다.
  2. 속도와 전력: Wi-Fi는 Gbps급 고속 전송이 가능하지만 전력 소모가 크고, Bluetooth는 상대적으로 저속(최대 수십 Mbps)이지만 저전력으로 배터리 효율성이 뛰어나 웨어러블 기기에 적합합니다.
  3. 연결 방식과 구조: Wi-Fi는 액세스 포인트(AP) 중심의 스타 토폴로지로 많은 기기가 동시 연결 가능하고, Bluetooth는 기기 간 직접 연결(P2P) 방식으로 주로 1:1 또는 소규모 그룹 연결에 특화되어 있습니다.

🤔 갑자기 궁금해진건데, bluetooth로는 인터넷을 연결 시킬 수 있는 걸까요?

네, Bluetooth로 인터넷 연결이 가능합니다. 스마트폰의 "블루투스 테더링" 기능을 사용하면 스마트폰이 인터넷 게이트웨이 역할을 하여 다른 기기(노트북, 태블릿 등)가 블루투스를 통해 인터넷에 접속할 수 있습니다. 다만, Wi-Fi 보다 속도가 현저히 느리고 전력 효율도 떨어져서 Wi-Fi가 불가능한 특수한 상황에서만 사용된다고 하네요.


ESP32 에서의 Wi-Fi

주요 스펙

ESP32의 Wi-Fi는 사물 인터넷(IoT) 애플리케이션에 최적화된 강력하고 유연한 무선 통신 기능을 제공합니다. ESP32의 주요 Wi-Fi 스펙은 다음과 같습니다.

  • 지원 표준 및 주파수: IEEE 802.11 b/g/n(Wi-Fi 4) 표준을 지원하며 2.4GHz 대역에서만 동작합니다. 5GHz는 지원하지 않지만 대부분의 IoT 용도에는 충분한 성능을 제공합니다.
  • 전송 속도 및 범위: 최대 150Mbps(802.11n HT40)의 데이터 전송 속도를 지원하며, 실제 처리량은 약 80-100Mbps 수준이고, 개방된 공간에서 최대 100-150m의 통신 범위를 가집니다.
  • 동작 모드: 스테이션(STA), 액세스 포인트(AP), STA+AP (동시 작동) 모드를 제공하여 네트워크 클라이언트, 네트워크 호스트, 또는 두 가지 역할 모두 수행할 수 있습니다.
  • 보안 및 프로토콜: WPA/WPA2 Personal 보안을 지원하고, TCP/IP 스택이 내장되어 있어 HTTP, HTTPS, MQTT, WebSocket 등 다양한 인터넷 프로토콜을 직접 사용할 수 있습니다.
  • 전력 관리: Wi-Fi 모뎀 슬립, 라이트 슬립, 딥 슬립 등 다양한 절전 모드를 지원하여 배터리 구동 IoT 기기에 최적화되어 있으며, 필요에 따라 Wi-Fi를 완전히 끄고 켤 수 있습니다.

작동 모드

ESP32의 Wi-Fi 기능에는 크게 액세스 포인트(Access Point, AP) 모드와 스테이션(Station, STA) 모드의 두 가지 주요 작동 모드가 있습니다. 먼저 용어에 대해 살펴보겠습니다.

용어 정의

액세스 포인트(Access Point, AP)와 스테이션(Station, STA)은 무선 통신 네트워크, 특히 Wi-Fi 환경에서 장치의 역할을 설명하는 핵심 용어입니다.

  • AP는 네트워크를 생성하고 관리하며, 다른 무선 장치들이 연결할 수 있도록 하는 중심 장치입니다. 집이나 사무실에서 사용하는 무선 라우터가 가장 흔한 AP의 예입니다.

  • STA는 기존에 존재하는 AP에 연결하여 네트워크 서비스를 이용하는 모든 무선 장치를 의미합니다. '클라이언트(Client)'라고도 불립니다.

Access Point(AP) 모드

AP 모드에서 ESP32는 다른 Wi-Fi 장치(예: 스마트폰, 노트북, 다른 ESP32 등)가 연결할 수 있는 자체 Wi-Fi 네트워크를 생성합니다.

💻 이미지 출처. ElectronicWings

SSID (네트워크 이름)와 비밀번호를 설정하여 네트워크를 만듭니다. 연결된 장치에 IP 주소를 할당합니다 (일반적으로 DHCP 서버 역할).

ESP32를 스마트폰 등으로 직접 제어하거나 설정할 때, ESP32를 소프트 AP로 사용하여 주변 장치들이 서로 통신하게 할 때 사용합니다.

Station(STA) 모드

STA 모드에서 ESP32는 일반적인 Wi-Fi 장치(예: 스마트폰, 노트북)처럼 작동하여 기존 Wi-Fi 네트워크 (예: 집이나 사무실의 라우터)에 연결합니다.

💻 이미지 출처. ElectronicWings

연결하고자 하는 네트워크의 SSID와 비밀번호를 사용합니다. 라우터로부터 IP 주소를 할당받아 인터넷 또는 로컬 네트워크의 다른 장치들과 통신합니다.

ESP32가 인터넷에 접속하여 데이터를 송수신하거나 클라우드 서비스에 연결할 때, 기존 홈 네트워크 내에서 다른 장치들과 통신해야 할 때 사용합니다.

동시 모드 (AP + STA)

ESP32는 이 두 가지 모드를 동시에 실행할 수도 있습니다. 자신의 AP를 생성하는 동시에, 기존 라우터에도 연결되어 클라이언트로 작동합니다.

ESP32가 인터넷에 연결되어 데이터를 받아오면서 (STA 모드), 동시에 이 데이터를 자체 AP에 연결된 로컬 장치에 제공해야 할 때, Wi-Fi 리피터(중계기) 기능을 구현하는 데 사용될 수 있습니다.


ESP32 Wi-Fi Station 실습

ESP32에서 ESP-IDF 환경을 사용하여 Wi-Fi Station으로 접속하는 테스트 코드를 작성해서 실습을 진행해보도록 하겠습니다. 아래는 참고 자료입니다.

코드 작성

1. 전역 변수 및 매크로 정의

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_wifi.h"

// Wi-Fi 접속 정보
#define WIFI_SSID "ssid"
#define WIFI_PASSWORD "password"
#define WIFI_MAXIMUM_RETRY 5

// FreeRTOS 이벤트 그룹 비트 정의
static EventGroupHandle_t s_wifi_event_group;
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1

static int s_retry_count = 0;
static const char *TAG = "WIFI_STATION";
  • WIFI_SSID, WIFI_PASSWORD: 접속하려는 AP(Access Point)의 SSID와 비밀번호를 정의합니다. 실제 사용할 정보로 변경해야 합니다.
  • s_wifi_event_group: FreeRTOS의 EventGroup을 사용하여 Wi-Fi 접속 상태를 비동기적으로(asynchronously) 모니터링합니다.
  • WIFI_CONNECTED_BIT, WIFI_FAIL_BIT: 접속 성공/실패 시 이벤트를 알리는 비트입니다.

2. 이벤트 핸들러 함수

Wi-Fi 드라이버 및 IP 스택에서 발생하는 이벤트를 처리하는 핵심 함수입니다.

/** 이벤트 핸들러 함수 */
static void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
{
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
        // Wi-Fi 드라이버가 시작되면, 접속을 시도합니다. 
        esp_wifi_connect();
    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
        // 접속이 끊어졌을 경우, 재접속을 시도합니다. 
        wifi_event_sta_disconnected_t* event = (wifi_event_sta_disconnected_t*) event_data;
        ESP_LOGI(TAG, "Disconnected reason: %d", event->reason);
        ESP_LOGI(TAG, "Disconnected. Reconnecting...");
        if (s_retry_count < WIFI_MAXIMUM_RETRY) {
            esp_wifi_connect();
            s_retry_count++;
            ESP_LOGI(TAG, "Retry to connect to the AP");
        } else {
            xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
        }
    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
        // IP 주소를 성공적으로 할당받으면, 접속 성공 비트를 설정합니다. 
        ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
        ESP_LOGI(TAG, "Connected to the AP, IP address: " IPSTR, IP2STR(&event->ip_info.ip));
        s_retry_count = 0;
        xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
    }
}
  • WIFI_EVENT_STA_START: Wi-Fi Station 모드 시작 시 esp_wifi_connect()를 호출하여 접속을 시작합니다.
  • WIFI_EVENT_STA_DISCONNECTED: 접속 실패/끊김 시 재시도 횟수를 확인하고 재접속을 시도합니다. 최대 횟수 초과 시 WIFI_FAIL_BIT를 설정합니다.
  • IP_EVENT_STA_GOT_IP: DHCP 서버로부터 IP 주소를 할당받으면 WIFI_CONNECTED_BIT를 설정하여 메인 함수에 접속 성공을 알립니다.

3. Wi-Fi 초기화 및 접속 함수

Wi-Fi 통신을 위한 스택 및 드라이버를 초기화하고 접속을 설정합니다. 코드를 작성하기 전에 이해하고 넘어가야 될 부분이 있습니다.

ESP32 Wi-Fi 이벤트 처리 구조

  1. TCP 스택에서 이벤트 발생: 네트워크 연결, 연결 해제, 데이터 수신 등의 네트워크 이벤트가 TCP 스택에서 발생하면 이벤트 신호가 생성되어 시스템에 알립니다.
  2. Event Task(기본 핸들러): Event Task는 WiFi Driver와 TCP 스택으로부터 이벤트를 받아서, 이를 사용자 정의 핸들러로 전달합니다.
  3. 사용자 애플리케이션으로 콜백 전달: Event Task는 등록된 사용자 콜백 함수나 이벤트를 Application Task로 전달하여 개발자가 작성한 코드에서 네트워크 상태 변화에 대응할 수 있게 합니다. 위에서 작성한 이벤트 핸들러 함수가 이에 해당하겠군요.
  4. Application Task에서 Wi-Fi Driver 제어: 사용자 애플리케이션은 이벤트를 받아 처리한 후, 필요에 따라 Wi-Fi Driver에 API 호출을 통해 연결, 연결 해제, 설정 변경 등의 제어 명령을 보냅니다.
  5. 순환 구조: Wi-Fi Driver의 상태 변화는 다시 이벤트를 생성하여 Event Task로 전달되는 순환 구조로, 이를 통해 네트워크 상태를 실시간으로 모니터링하고 대응할 수 있는 이벤트 기반 시스템을 구성합니다.

정리하자면, WiFi Driver와 TCP/IP은 Event task으로 이벤트를 전송하고, Event task은 해당 이벤트를 Application task에 알립니다. 애플리케이션 작업은 WiFi 드라이버 API를 호출하여 일부 작업을 수행하고 이벤트 작업에서 전달된 WiFi 이벤트를 수신합니다.

이제 코드를 보면서 설명하도록 하겠습니다.

void wifi_init_sta(void)
{
    // 이벤트 그룹 생성
    s_wifi_event_group = xEventGroupCreate();

    // TCP/IP 스택 초기화
    ESP_ERROR_CHECK(esp_netif_init());

    // 기본 이벤트 루트 정의
    ESP_ERROR_CHECK(esp_event_loop_create_default());

    // Wi-Fi Station 네트워크 인터페이스 생성
    esp_netif_create_default_wifi_sta();

    // 이벤트 핸들러 등록
    esp_event_handler_instance_t instance_any_id;
    esp_event_handler_instance_t instance_got_ip;
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_any_id));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
                                                        IP_EVENT_STA_GOT_IP,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_got_ip));

    // Wi-Fi 드라이버 초기화 및 기본 설정
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    // Wi-Fi 설정 (SSID/PASS 및 모드)
    wifi_config_t wifi_config = {
        .sta = {
            .ssid = WIFI_SSID,
            .password = WIFI_PASSWORD,
        },
    };
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));

    // Wi-Fi 드라이버 시작
    ESP_ERROR_CHECK(esp_wifi_start());
    ESP_LOGI(TAG, "Wi-Fi Driver Started");

    // 접속 상태 대기 및 결과 처리
    EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
                                          WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
                                          pdFALSE,         // 비트를 클리어하지 않음
                                          pdFALSE,         // 두 비트 중 하나라도 설정되면 반환
                                          portMAX_DELAY);  // 무한 대기
    if (bits & WIFI_CONNECTED_BIT) {
        ESP_LOGI(TAG, "Connected to the AP");
    } else if (bits & WIFI_FAIL_BIT) {
        ESP_LOGI(TAG, "Failed to connect to the AP");
    } else {
        ESP_LOGI(TAG, "Unknown event");
    }
}
  • TCP/IP 스택 초기화 (esp_netif_init)
  • 기본 이벤트 루프 생성 (esp_event_loop_create_default): WiFi 및 TCP/IP 이벤트를 수신하는 이벤트 작업을 기본 이벤트 루프라고 합니다. 시스템 이벤트를 이벤트 작업으로 전송할 수 있도록 기본 이벤트 루프를 생성해야 합니다.
  • esp_netif_create_default_wifi_sta: WiFi 드라이버와 TCP/IP 스택을 바인딩하는 Station 네트워크 인터페이스 인스턴스를 생성합니다.
  • esp_event_handler_instance_register로 이전에 정의한 event_handler를 Wi-Fi 및 IP 이벤트에 연결합니다.
  • esp_wifi_init: WiFi 드라이버 작업을 생성하고 WiFi 드라이버를 초기화 합니다.
  • esp_wifi_set_mode(WIFI_MODE_STA)로 Station 모드를 설정합니다.
  • esp_wifi_set_config로 SSID/Password를 설정합니다.
  • esp_wifi_start()로 Wi-Fi 드라이버 작업을 시작합니다. WiFi를 시작하고 AP에 연결합니다.
  • xEventGroupWaitBits를 사용하여 접속 성공/실패 이벤트가 발생할 때까지 메인 흐름을 대기시킵니다.

ESP32가 AP 연결에 실패하면 이벤트 핸들러가 이벤트 그룹의 WIFI_FAIL_BIT를 설정하여 애플리케이션 작업을 활성화하고 실패 메시지를 출력합니다.

ESP32가 AP에 성공적으로 연결하고 IP 주소를 가져오면 이벤트 그룹의 WIFI_CONNECTED_BIT 비트가 설정되고 애플리케이션의 차단이 해제되어 할당된 IP 주소를 출력합니다.


🎯 참고. FreeRTOS의 Event Group

FreeRTOS의 Event Group은 태스크(Task) 간의 동기화 및 통신을 위해 사용되는 강력한 기능입니다. 여러 이벤트(비트)의 조합을 기다리거나 설정함으로써 태스크의 실행 흐름을 제어할 수 있습니다.

Event Group의 주요 동작 및 특징은 다음과 같습니다.

  1. 이벤트 비트 (Event Bits): Event Group의 각 비트(0에서 23 또는 7까지)는 개별적인 이벤트를 나타냅니다. 태스크는 필요한 이벤트를 비트마스크(Bitmask) 형태로 지정하여 기다립니다.
  2. 이벤트 설정 (xEventGroupSetBits()): 하나 이상의 비트를 설정하여 이벤트를 발생시킵니다. 이 함수를 호출하면, 현재 이 이벤트를 기다리고 있던 모든 태스크를 확인하고, 대기 조건이 충족된 태스크는 즉시 Ready 상태로 전환됩니다.
  3. 이벤트 대기 (xEventGroupWaitBits()): 이 함수는 Event Group의 핵심으로, 태스크가 이벤트를 기다릴 때 여러 옵션을 제공합니다. 대기 모드, 클리어 옵션, 타임 아웃 설정이 가능합니다.
EventBits_t xEventGroupWaitBits(
    EventGroupHandle_t xEventGroup,    // 대상 이벤트 그룹 핸들
    const EventBits_t uxBitsToWaitFor, // 기다릴 비트(mask)
    BaseType_t xClearOnExit,           // 비트 자동 클리어 여부
    BaseType_t xWaitForAllBits,        // 모든 비트가 필요할지 여부
    TickType_t xTicksToWait            // 최대 대기 시간
);

사용 예제 -> 이벤트 그룹은 태스크 간 동기화와 상태 공유에 아주 유용

#define BIT_0 (1 << 0)
#define BIT_1 (1 << 1)

EventGroupHandle_t myEventGroup;

void Task1(void *pvParameters) {
    // BIT_0가 세트될 때까지 최대 100ms 대기
    EventBits_t bits = xEventGroupWaitBits(
        myEventGroup,
        BIT_0,
        pdTRUE,     // 태스크가 이벤트를 확인한 후 비트를 자동으로 클리어
        pdFALSE,    // 하나라도 세트되면 OK
        pdMS_TO_TICKS(100)
    );

    if(bits & BIT_0) {
        // BIT_0가 세트되어서 리턴됨
        printf("BIT_0 발생!\n");
    }
}

Event Group은 주로 다음과 같은 시나리오에서 유용합니다.

  1. 다중 조건 동기화 (AND 모드): 시스템 초기화 시, (A) 네트워크 모듈 준비, (B) 센서 초기화 완료, (C) 사용자 설정 로드 완료의 세 가지 조건(이벤트)이 모두 완료된 후에만 메인 태스크를 시작할 때 사용합니다.
  2. 다중 트리거 (OR 모드): 사용자 입력 태스크가 (A) 버튼 클릭 또는 (B) 터치 스크린 이벤트 중 어느 하나만 발생해도 동작해야 할 때 사용합니다.

Event Group은 단순한 Binary Semaphore나 Mutex로는 처리하기 어려운 복잡한 다중 이벤트 동기화 문제를 효율적으로 해결할 수 있게 해줍니다.

4. 메인 애플리케이션 함수

프로그램의 진입점(Entry Point)입니다.

void app_main(void)
{
    // 1. NVS (Non-Volatile Storage) 초기화
    // Wi-Fi 설정 및 기타 데이터 저장을 위해 필요
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);

    ESP_LOGI(TAG, "ESP32 Wi-Fi Station Mode Start");

    // 2. Wi-Fi Station 초기화 및 접속 시작
    wifi_init_sta();
    
    // 3. (접속 성공 후) 필요한 작업 수행
    // 예: 서버 접속, 데이터 전송 등
}
  • nvs_flash_init(): Wi-Fi 설정 정보를 플래시 메모리에 저장하기 위한 NVS를 초기화합니다.
  • wifi_init_sta(): 위에서 정의한 Wi-Fi 접속 함수를 호출합니다.

참고. 와이파이 스캔 테스트

// Wi-Fi 스캔
wifi_scan_config_t scan_config = {
    .ssid = NULL,
    .bssid = NULL,
    .channel = 0,
    .show_hidden = true,
    .scan_type = WIFI_SCAN_TYPE_ACTIVE,
};
ESP_ERROR_CHECK(esp_wifi_scan_start(&scan_config, true)); // blocking 방식

uint16_t ap_count = 0;
esp_wifi_scan_get_ap_num(&ap_count);
ESP_LOGI(TAG, "Found %d access points", ap_count);

wifi_ap_record_t ap_info[ap_count];
esp_wifi_scan_get_ap_records(&ap_count, ap_info);

for (int i = 0; i < ap_count; i++) {
    ESP_LOGI(TAG, "AP %d: SSID: %s, RSSI: %d", i, ap_info[i].ssid, ap_info[i].rssi);
}

주의할 점. Wi-Fi 드라이버 시작 esp_wifi_start() 이후에 스캔 테스트를 할 것.

결과 확인

공유기를 통한 Wi-Fi 연결 테스트: 실패

I (697) wifi:mode : sta (6c:c8:40:34:97:40)
I (707) wifi:enable tsf
I (707) WIFI_STATION: Wi-Fi Driver Started
I (3117) WIFI_STATION: Disconnected reason: 201
I (3117) WIFI_STATION: Disconnected. Reconnecting...
I (3127) WIFI_STATION: Retry to connect to the AP
I (5537) WIFI_STATION: Disconnected reason: 201
I (5537) WIFI_STATION: Disconnected. Reconnecting...
I (5537) WIFI_STATION: Retry to connect to the AP
I (7947) WIFI_STATION: Disconnected reason: 201
I (7947) WIFI_STATION: Disconnected. Reconnecting...
I (7947) WIFI_STATION: Retry to connect to the AP
I (10367) WIFI_STATION: Disconnected reason: 201
I (10367) WIFI_STATION: Disconnected. Reconnecting...
I (10367) WIFI_STATION: Retry to connect to the AP
I (12777) WIFI_STATION: Disconnected reason: 201
I (12777) WIFI_STATION: Disconnected. Reconnecting...
I (12777) WIFI_STATION: Retry to connect to the AP
I (15187) WIFI_STATION: Disconnected reason: 201
I (15187) WIFI_STATION: Disconnected. Reconnecting...
I (15187) WIFI_STATION: Failed to connect to the AP
I (15197) main_task: Returned from app_main()
  • ESP32가 STA 모드로 시작. Wi-Fi 드라이버 시작
  • 연결 시도 및 반복 실패. Reason 201은 WIFI_REASON_NO_AP_FOUND 즉, AP를 찾지 못함을 의미

문제 원인 후보로는 다음과 같습니다.

  • SSID 오타: 대소문자, 공백 하나만 달라도 다른 네트워크로 인식합니다. (이거는 몇 번을 확인해도 맞는 거 같은데...)
  • 5GHz 연결 문제: ESP32는 2.4GHz만 지원합니다. 공유기가 같은 SSID를 2.4GHz / 5GHz에서 동시에 쓰는 경우가 많아요. (해당 와이파이를 확인해보니 채널: 2 (2.4GHz, 20MHz), 즉 2.4GHz 대역에서 동작하고 있는게 맞는 거 같다)
  • 공유기 SSID를 MyWiFi_2G 같은 식으로 2.4GHz 전용 이름으로 사용해보면 어떨까? (이것도 실패)
  • 전원/거리 문제: ESP32와 공유기 사이 거리 멀거나 전파 간섭이 심하면 RSSI가 낮아서 AP를 못 찾음. (확인 필요, 공유기 앞에 가서 테스트 해봐야 될 듯)
  • 보안 불일치: ESP32 기본값은 WPA2 이상만 연결 허용입니다. 만약 AP가 WPA1(WPA-PSK)이면, 기본 threshold 설정에서는 연결 시도조차 하지 않을 수 있음. (아마 이 문제인거 같은데)

ESP32 기본값은 WIFI_AUTH_WPA2_PSK이므로, WPA1 공유기와 연결하려면 threshold를 낮춰야 합니다. 그래서 "WIFI_AUTH_WPA_PSK" 라고 설정했지만 그래도 안되네요...

공유기 설정으로 들어가서 확인을 정확히 해봐야 될 거 같습니다.

참고. SK 공유기 설정 확인하기
참고. Mac에서 Wi-Fi 주파수 확인 방법: Option(Alt) 키 + 메뉴바 Wi-Fi 아이콘 클릭

음... 2.4G랑 5G 모두 지원하는 거 같고... 보안 설정은 “WPA-Mixed”, 이 방식은 WPA (TKIP) 와 WPA2 (CCMP/AES) 를 동시에 지원하는 모드 입니다. 따라서 보안 불일치 문제도 아닌거 같네요.

마지막으로 거리 문제. 방을 열고 거실에 있는 공유기 앞에 가니까 엇. 연결이 되네요.

I (707) WIFI_STATION: Wi-Fi Driver Started
I (707) WIFI_STATION: Found 0 access points
I (887) wifi:new:<2,0>, old:<1,0>, ap:<255,255>, sta:<2,0>, prof:1, snd_ch_cfg:0x0
I (887) wifi:state: init -> auth (0xb0)
I (897) wifi:state: auth -> assoc (0x0)
I (897) wifi:state: assoc -> run (0x10)
I (917) wifi:connected with SK_WiFiGIGA aid = 5, channel 2, BW20, bssid = xx:xx:xx:xx:xx:xx
I (917) wifi:security: WPA2-PSK, phy: bgn, rssi: -79
I (917) wifi:pm start, type: 1

I (927) wifi:dp: 1, bi: 102400, li: 3, scale listen interval from 307200 us to 307200 us
I (987) wifi:AP's beacon interval = 102400 us, DTIM period = 3
I (2957) esp_netif_handlers: sta ip: 192.168.35.143, mask: 255.255.255.0, gw: 192.168.35.1
I (2957) WIFI_STATION: Connected to the AP, IP address: 192.168.35.143
I (2957) WIFI_STATION: Connected to the AP
I (2957) main_task: Returned from app_main()

"SK_WiFiGIGA" SSID로 WPA2-PSK 보안 방식으로 연결이 성공되었음을 알 수 있습니다. 그리고 DHCP를 통해 IP 주소 할당 완료 (192.168.35.143). 게이트웨이 192.168.35.1 → 인터넷 통신 가능합니다.

와... 겨우 방문 하나를 사이에 두고 연결이 잡히지 않았던 거라니... 이래서 안테나가 필요했던 거군요... 아무튼 원인을 알게 되었기 때문에 기분은 좋네요.


iOS 핫스팟을 통한 Wi-Fi 연결 테스트: 정상적으로 연결됨 (참고로, "호환성 최대화"를 활성화 해줘야 2.4GHz까지 지원된다고 함)

I (707) WIFI_STATION: Wi-Fi Driver Started
I (1357) wifi:new:<6,0>, old:<1,0>, ap:<255,255>, sta:<6,0>, prof:1, snd_ch_cfg:0x0
I (1357) wifi:state: init -> auth (0xb0)
I (1367) wifi:state: auth -> assoc (0x0)
I (1377) wifi:state: assoc -> run (0x10)
I (1407) wifi:connected with MyPhone, aid = 1, channel 6, BW20, bssid = xx:xx:xx:xx:xx:xx
I (1407) wifi:security: WPA2-PSK, phy: bgn, rssi: -86
I (1407) wifi:pm start, type: 1

I (1407) wifi:dp: 1, bi: 102400, li: 3, scale listen interval from 307200 us to 307200 us
I (1487) wifi:AP's beacon interval = 102400 us, DTIM period = 1
I (2447) esp_netif_handlers: sta ip: 172.20.10.9, mask: 255.255.255.240, gw: 172.20.10.1
I (2447) WIFI_STATION: Connected to the AP, IP address: 172.20.10.9
I (2447) WIFI_STATION: Connected to the AP
I (2447) main_task: Returned from app_main()
  • Wi-Fi 드라이버가 시작됨.
  • 새로운 Wi-Fi 모드 정보. ESP32는 STA 모드로 동작하고 있음.
  • STA 모드 상태 변화: init → auth → assoc → run. 순서대로 인증(auth) → 연결 시도(assoc) → 연결 완료(run)
  • MyPhone(iPhone 13) 핫스팟과 연결 완료. 인증 방식: WPA2-PSK. 채널 6, RSSI -86 (신호 세기, 약간 약함)
  • DHCP로 IP 주소 172.20.10.9 할당됨. 이제 ESP32가 인터넷 사용 가능

결과적으로 ESP32가 iOS 핫스팟에 정상 연결되었고요. WPA2-PSK 인증 문제 없고요. IP 주소도 정상적으로 할당되었습니다.


ESP32 Wi-Fi Access Point 실습

ESP32를 Wi-Fi 액세스 포인트 (Access Point, AP)로 동작시키고, 다른 장치가 이 AP에 연결할 수 있는지 테스트 해보는 실습을 진행하겠습니다.

참고. ESP-IDF 예시 코드: https://github.com/espressif/esp-idf/tree/master/examples/wifi/getting_started/softAP

코드 작성

결과 확인


참고 자료

profile
행동하는 바보가 돼라. 생각을 즉시 행동으로 옮기는 사람이 되어라

0개의 댓글