ESP32를 처음 사용할 때는 정말 재미있습니다.
LED 하나 켜는 것도 신기하고, 센서 값을 읽는 것도 금방 됩니다.
그런데 기능이 조금만 늘어나면 상황이 달라집니다.
LED도 제어해야 하고
센서도 읽어야 하고
버튼 입력도 받아야 하고
여기에 Wi-Fi까지 붙이면
코드가 점점 복잡해지고, 어디서 문제가 생겼는지 찾기 어려워집니다.
이 문제의 근본 원인은 단 하나입니다.
바로
“모든 기능이 loop() 하나에 몰려 있기 때문”입니다.
기존 방식의 한계: loop() 하나로는 부족하다
기존 Arduino 구조는 이렇게 생깁니다.
loop() {
readSensor();
updateDisplay();
sendWiFi();
}
처음에는 문제가 없어 보입니다.
하지만 실제로는 다음과 같은 문제가 발생합니다.
센서를 읽는 동안 Wi-Fi가 멈추고
Wi-Fi 전송 중에는 화면이 멈추고
버튼 입력도 놓치게 됩니다
즉, 모든 기능이 서로 발목을 잡게 됩니다.
해결 방법: Task로 쪼개라
ESP32는 이 문제를 해결하기 위해
FreeRTOS 기반으로 동작합니다.
이 말은 무엇이냐면
“여러 개의 loop를 동시에 실행할 수 있다”는 의미입니다.
이때 사용하는 개념이 바로 Task입니다.
Task를 이해하는 가장 쉬운 방법
Task는 이렇게 생각하면 됩니다.
“각 기능을 별도의 Arduino 스케치로 나눈다”
예를 들어
LED 제어 코드
센서 읽기 코드
버튼 입력 코드
Wi-Fi 전송 코드
이걸 각각 따로 실행한다고 생각하면 됩니다.
Task 기본 구조
Task는 아래처럼 생깁니다.
void task(void * parameter) {
// 여기에 setup 역할을 하는 코드
while (true) {
// 여기에 loop 역할을 하는 코드
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
구조는 매우 단순합니다.
초기 실행 부분 + 무한 루프
Arduino와 거의 동일합니다.
Task 생성 방법
ESP32에서는 아래 함수로 Task를 만듭니다.
xTaskCreatePinnedToCore(
taskFunction,
"Task Name",
2048, // Stack Size
NULL,
1, // Priority
NULL,
1 // Core
);
이 코드에서 중요한 요소는 4가지입니다.
Task Function → 실행할 코드
Stack Size → 메모리 크기
Priority → 우선순위
Core → 어느 CPU에서 실행할지
Core 개념 (매우 중요)
ESP32는 듀얼코어입니다.
Core 0 → Wi-Fi, Bluetooth 등 시스템
Core 1 → 사용자 코드
따라서 일반적으로는
모든 Task를 Core 1에서 실행하는 것이 안정적입니다.
실제 멀티태스킹 예제
LED, 버튼, 시리얼 출력이 동시에 동작하는 코드입니다.
#define LED_PIN 2
#define BUTTON_PIN 4
void ledTask(void * parameter) {
pinMode(LED_PIN, OUTPUT);
while (true) {
digitalWrite(LED_PIN, HIGH);
vTaskDelay(500 / portTICK_PERIOD_MS);
digitalWrite(LED_PIN, LOW);
vTaskDelay(500 / portTICK_PERIOD_MS);
}
}
void buttonTask(void * parameter) {
pinMode(BUTTON_PIN, INPUT_PULLUP);
while (true) {
if (digitalRead(BUTTON_PIN) == LOW) {
Serial.println("Button pressed");
}
vTaskDelay(100 / portTICK_PERIOD_MS);
}
}
void serialTask(void * parameter) {
while (true) {
Serial.println("System running...");
vTaskDelay(2000 / portTICK_PERIOD_MS);
}
}
void setup() {
Serial.begin(115200);
xTaskCreatePinnedToCore(ledTask, "LED", 2048, NULL, 1, NULL, 1);
xTaskCreatePinnedToCore(buttonTask, "BUTTON", 2048, NULL, 1, NULL, 1);
xTaskCreatePinnedToCore(serialTask, "SERIAL", 2048, NULL, 1, NULL, 1);
}
void loop() {}
이 코드의 핵심은 하나입니다.
각 기능이 완전히 독립적으로 동작한다는 점입니다.
반드시 알아야 할 핵심 3가지
첫 번째
vTaskDelay는 필수입니다
이걸 쓰지 않으면
한 Task가 CPU를 독점해서 다른 Task가 멈춥니다
두 번째
delay()는 가능하면 쓰지 않습니다
FreeRTOS 구조에서는 비효율적입니다
세 번째
Task 간 간섭을 최소화해야 합니다
특히 하나의 변수를 여러 Task에서 동시에 쓰면 문제가 생깁니다
멀티태스킹 구조로 바꾸면 생기는 변화
기존 구조
센서 → Wi-Fi → 디스플레이 → 반복
멀티태스킹 구조
Sensor Task → 센서만 담당
Network Task → 통신만 담당
Display Task → 화면만 담당
Control Task → 입력만 담당
이렇게 완전히 분리됩니다.
IoT 프로젝트에서는 필수 구조다
ESP32로 다음을 동시에 한다면
Wi-Fi
BLE
센서
OLED
배터리 관리
이건 더 이상 단일 loop로 해결할 수 있는 수준이 아닙니다.
멀티태스킹 구조가 아니라면
언젠가는 반드시 꼬입니다.
결론
ESP32의 멀티태스킹은 단순한 기능이 아닙니다.
“코드를 나누는 기술”이 아니라
“시스템을 설계하는 방식”입니다.
기능이 2개 이상이라면
이미 멀티태스킹을 써야 하는 단계입니다.
한 줄 정리
ESP32 Task는
“복잡한 시스템을 기능별로 나눠서 동시에 실행하는 구조”
'DIY Electronics' 카테고리의 다른 글
| 마이크로 컨트롤러 커스텀 보드를 공부하게된 계기 (1) | 2026.05.13 |
|---|---|
| ESP32에서 Task를 이용한 Multi-tasking 예제 (0) | 2026.05.06 |
| ESPHome 입문 가이드 - 로컬 스마트홈 기기를 만드는 가장 쉬운 방법 (1) | 2026.04.15 |
| ESP32 Online Tools - IDE 없이 개발하는 방법 (링크 포함) (2) | 2026.04.14 |
| LD1117 사용자 가이드 (0) | 2026.04.13 |
