ESP32 FreeRTOS 튜토리얼 가이드 6부작 5
FreeRTOS를 사용하여 ESP32에서 실시간 애플리케이션을 구축하는 방법을 배워보세요. 태스크 생성, 우선순위 처리, 메모리 관리, 태스크 간 통신에 관한 실용적인 튜토리얼을 살펴보세요. 각 예제는 실제 하드웨어에서 테스트되어 멀티태스킹을 숙달하고 ESP32의 듀얼 코어 성능을 최대한 활용할 수 있도록 도와줍니다.
ESP32 FreeRTOS(1부): FreeRTOS 및 작업 관리 소개
ESP32 FreeRTOS(2부): 스케줄러 및 작업 관리 이해
ESP32 FreeRTOS(3부): 작업 우선순위 및 스택 관리 설명
ESP32 FreeRTOS(4부): 작업 간 통신 설명 | 큐, 세마포어 및 이벤트 그룹
ESP32 FreeRTOS(5부): 소프트웨어 타이머 및 작업 알림 설명
ESP32 FreeRTOS(6부): ESP-IDF에서 작업을 일시 중지, 재개 및 삭제하는 방법
ESP32의 FreeRTOS 소프트웨어 타이머 및 작업 알림
FreeRTOS는 ESP32의 가장 강력한 기능 중 하나입니다. 여러 작업을 실행하고, 타이밍을 관리하고, 작업 간 통신을 간편하게 할 수 있습니다. 이전 튜토리얼에서는 작업을 생성하고, 우선순위를 설정하고, 작업 간에 데이터를 전송하는 방법을 배웠습니다.
이 튜토리얼에서는 FreeRTOS 소프트웨어 타이머 와 ESP-IDF의 작업 알림을 살펴보겠습니다 . 두 가지 모두 큐나 세마포어를 사용하지 않고 고정된 간격으로 작업을 수행하거나 작업 간에 빠른 신호를 전송하려는 경우 매우 유용합니다.
소프트웨어 타이머를 생성하고 , 타이머 콜백을 처리하고 , 가벼운 통신을 위해 작업 알림을 사용하는 방법을 배웁니다 . 이 튜토리얼을 마치면 FreeRTOS의 이러한 기능들을 활용하여 반응성이 뛰어나고 효율적인 ESP32 애플리케이션을 구축할 수 있을 것입니다.

ESP32의 FreeRTOS 소프트웨어 타이머 및 작업 알림
- 목차
- FreeRTOS 타이머 및 작업 알림 소개
- FreeRTOS 소프트웨어 타이머 이해
- ESP-IDF에서 소프트웨어 타이머 생성 및 관리
- FreeRTOS 작업 알림
- 타이머와 작업 알림 결합
- 일반적인 문제 및 문제 해결
- 결론
FreeRTOS 타이머 및 작업 알림 소개
FreeRTOS에서 타이밍과 동기화는 작업 관리에 중요한 역할을 합니다. 때로는 LED 깜빡임, 센서 읽기, 몇 초마다 서버로 데이터 전송 등 일정한 간격으로 실행되는 함수가 필요할 수 있습니다. vTaskDelay()로 별도의 작업을 생성하는 대신 FreeRTOS 소프트웨어 타이머를 사용할 수 있습니다.
마찬가지로, 두 작업이 빠르고 효율적으로 통신 해야 할 때 작업 알림은 큐나 세마포어에 대한 가벼운 대안을 제공합니다. 이 섹션에서는 이러한 기능이 무엇이고 ESP32 FreeRTOS 애플리케이션에서 왜 그렇게 유용한지 알아보겠습니다.
FreeRTOS에서 타이머를 사용하는 이유
타이머는 주기적으로 또는 특정 시간 지연 후에 동작을 수행 하려는 경우에 사용됩니다 . 예를 들면 다음과 같습니다.
- 1초마다 LED 켜고 끄기
- 100ms마다 센서 데이터 확인
- 서버에 하트비트 메시지 보내기
기존 작업에서는 vTaskDelay() 또는 vTaskDelayUntil()을 사용할 수 있지만, 이 경우 지연 시간 동안 작업이 차단된 상태로 유지됩니다. 반면 소프트웨어 타이머는 CPU를 해제합니다. 타이머는 백그라운드에서 실행되며 시간이 만료될 때만 콜백 함수를 호출합니다.
이는 CPU 사용량이 줄어들고 , 타이밍 정확도가 높아지고 , 코드가 더 깔끔해진다 는 것을 의미하는데 , 특히 반복 작업의 경우 그렇습니다.
하드웨어 타이머와 소프트웨어 타이머의 차이점
ESP32의 하드웨어 타이머와 소프트웨어 타이머의 차이점을 이해하는 것이 중요합니다.
| 특징 | 하드웨어 타이머 | 소프트웨어 타이머 |
| 실행 중 | 마이크로컨트롤러의 내부 하드웨어 카운터 | FreeRTOS 커널(타이머 서비스 작업) |
| 정확성 | 매우 높음 | 시스템 틱 속도에 따라 다릅니다. |
| 인터럽트 기반 | 예 | 아니요, 소프트웨어에서 처리합니다 |
| 유연성 | 제한적(고정된 개수) | 매우 유연함 |
| 콜백 컨텍스트 | ISR(인터럽트) | 일반 작업 컨텍스트 |
| CPU 사용량 | 최소 | CPU 시간을 사용합니다(커널을 통해) |
- 하드웨어 타이머는 정확하고 지연 시간이 짧은 타이밍 (PWM이나 센서 샘플링 등) 에 가장 적합합니다 .
- 소프트웨어 타이머는 밀리초 단위의 타이밍 정밀도가 허용되는 일반적인 주기적 작업 에 가장 적합합니다 .
ESP32는 두 가지 옵션을 모두 제공하며, FreeRTOS 소프트웨어 타이머는 대부분의 스케줄링 및 제어 작업에 이상적입니다.
FreeRTOS의 작업 알림이란 무엇입니까?
작업 알림은 작업 간에 신호를 주고받는 빠르고 가벼운 방법입니다 . FreeRTOS의 각 작업에는 다른 작업이나 ISR(인터럽트 서비스 루틴)에 의해 업데이트될 수 있는 기본 알림 값이 있습니다.
작업 알림은 큐나 세마포어를 사용할 필요 없이 특정 작업에 대한 직접 메시지 라고 생각할 수 있습니다.
작업 알림은 다음과 같은 기능을 제공합니다.
- 차단된 작업 깨우기
- 간단한 데이터(카운터나 플래그 등)를 보냅니다.
- 효율성을 위해 이진 또는 카운팅 세마포어를 교체
예를 들어, 한 작업은 타이머가 만료되거나, 데이터가 준비되거나, 이벤트가 발생할 때 다른 작업에 알릴 수 있습니다.
이러한 방식은 큐나 세마포어보다 빠르고 메모리 사용량이 적어 리소스가 제한된 실시간 ESP32 애플리케이션에 적합합니다.
FreeRTOS 소프트웨어 타이머 이해
FreeRTOS 소프트웨어 타이머를 사용하면 별도의 작업을 생성하지 않고도 설정된 시간 간격 후에 특정 기능을 자동으로 실행할 수 있습니다. 이 타이머는 FreeRTOS 커널에서 전적으로 관리되므로 ESP32 에서 매우 효율적이고 사용하기 쉽습니다 .
이 섹션에서는 이러한 타이머가 어떻게 작동하는지, 콜백 함수를 만들고 처리하는 방법, 그리고 타이머를 시작할 때 내부적으로 어떤 일이 일어나는지 살펴보겠습니다.
ESP32 FreeRTOS에서 소프트웨어 타이머가 작동하는 방식
FreeRTOS의 소프트웨어 타이머는 커널에서 생성된 시스템 틱을 계산하여 작동합니다 . 타이머가 만료되면 FreeRTOS는 자동으로 우리가 정의한 콜백 함수를 호출합니다.
무슨 일이 일어나는지 간단히 설명하면 다음과 같습니다.
- xTimerCreate() 을 사용하여 타이머를 만듭니다.
- xTimerStart() 을 사용하여 타이머를 시작하세요.
- FreeRTOS는 타이머를 특수 타이머 목록에 추가합니다 .
- 타이머가 시간 초과 값에 도달하면 커널은 콜백 함수를 예약합니다.
- 콜백은 인터럽트가 아닌 백그라운드 작업 에서 실행됩니다.
하드웨어 타이머와 달리 소프트웨어 타이머는 실시간으로 실행되지 않습니다. FreeRTOS 설정에서 설정된 틱 속도 (일반적으로 1000Hz = 1ms 틱)에 따라 달라집니다.
이 속도는 LED 깜박임, 센서 읽기, 또는 시간 제한 이벤트와 같은 대부분의 범용 작업에 충분히 정확합니다.
타이머 콜백 함수
FreeRTOS의 모든 소프트웨어 타이머에는 콜백 함수가 있어야 합니다 . 이 함수는 타이머가 만료될 때 실행되는 함수입니다.
함수는 다음과 같이 정의됩니다.
void vTimerCallback( TimerHandle_t xTimer );
이 함수 내에서는 다음을 수행할 수 있습니다.
- LED 토글
- 작업에 알림 보내기
- 타이머를 다시 시작하거나 중지합니다
- 다른 작은 작업을 수행합니다.
예:
void myTimerCallback(TimerHandle_t xTimer)
{
printf("Timer expired! Performing action...\n");
}
타이머를 생성할 때 다음 콜백을 첨부합니다.
TimerHandle_t myTimer = xTimerCreate("MyTimer", pdMS_TO_TICKS(1000), pdTRUE, 0, myTimerCallback);
즉, 타이머가 만료되면 콜백이 1000ms(1초)마다 실행됩니다.
참고: 콜백은 타이머 서비스 작업의 컨텍스트에서 실행되므로 여기서는 길거나 차단되는 작업을 피하세요.
원샷 및 자동 재장전 타이머
FreeRTOS는 두 가지 유형의 소프트웨어 타이머를 지원합니다.
| 유형 | 설명 | 예시 사용 |
| 원샷 타이머 | 시작 시 한 번만 실행됩니다. 수동으로 다시 시작해야 합니다. | 지연된 시작 작업 또는 시간 초과 이벤트 |
| 자동 재장전 타이머 | 만료 후 자동으로 다시 시작됩니다. | 주기적인 LED 깜박임 또는 센서 판독 |
타이머를 생성하는 동안 이 매개변수를 사용하여 유형을 정의할 수 있습니다.
xTimerCreate("MyTimer", pdMS_TO_TICKS(1000), pdTRUE, 0, myTimerCallback);
- 자동 재장전 타이에 pdTRUE 사용
- 원샷 타이머에 pdFALSE 사용
이를 통해 매우 유연하게 동작할 수 있습니다. 동일한 콜백도 타이머 유형에 따라 다르게 동작할 수 있습니다.
타이머 서비스 작업
FreeRTOS의 모든 소프트웨어 타이머는 특수 타이머 서비스 작업 ( 타이머 데몬 작업 이라고도 함 )에 의해 관리됩니다.
이 작업은 백그라운드에서 자동으로 실행되며 다음을 처리합니다.
- 타이머 생성 및 삭제
- 타이머 시작 및 중지
- 타이머 콜백 실행
FreeRTOS 스케줄러를 시작하면 이 서비스 태스크가 자동으로 생성됩니다. 이 태스크의 우선순위와 스택 크기는 FreeRTOSConfig.h 파일 내 두 개의 매크로로 설정됩니다:
#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1)
#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE * 2)
타이머 콜백이 스택 공간을 많이 사용하지 않는 한 일반적으로 이러한 설정을 수정할 필요는 없습니다.
*참고: 모든 타이머 콜백은 이 단일 서비스 작업에서 실행되므로, 그 안에 시간이 많이 걸리는 코드를 작성하지 마세요. 다른 타이머가 지연될 수 있습니다.
ESP-IDF에서 소프트웨어 타이머 생성 및 관리
FreeRTOS는 타이머 생성 , 시작 , 중지 및 재설정을 위한 바로 사용 가능한 API를 제공합니다 . 이 섹션에서는 타이머를 생성하고, 콜백을 연결하고, 타이머 동작을 제어하고, ESP32 보드에서 타이머가 제대로 작동하는지 확인하는 방법을 살펴보겠습니다.
소프트웨어 타이머를 만드는 단계
FreeRTOS에서 소프트웨어 타이머를 만드는 데는 4가지 주요 단계가 포함됩니다 .
1. 콜백 함수를 정의합니다.
이 함수는 타이머가 만료되면 자동으로 실행됩니다.
예: void myTimerCallback(TimerHandle_t xTimer)
2. 타이머 핸들 만들기 타이머를 만들고 핸들에 할당하는 데
xTimerCreate()를 사용하여 타이머를 생성하고 핸들에 할당합니다.
TimerHandle_t myTimer;
myTimer = xTimerCreate("MyTimer", pdMS_TO_TICKS(1000), pdTRUE, (void *)0, myTimerCallback);
매개변수 설명:
- Name : 디버깅을 위한 선택적 이름입니다.
- Period : 틱 단위의 시간 간격.
- Auto-reload : 반복 타이머의 경우 pdTRUE, 일회성의 경우 pdFALSE입니다.
- 타이머 ID : 타이머를 식별하는 데 사용됩니다(NULL 또는 포인터가 될 수 있음).
- 콜백 : 타이머가 만료되면 실행할 함수입니다.
3. 타이머가 성공적으로 생성되었는지 확인하세요
if (myTimer == NULL) printf("Timer creation failed!\n"); else printf("Timer created successfully!\n");
4. 타이머 시작
타이머는 생성된 후 자동으로 시작되지 않습니다.
다음과 같이 시작해야 합니다: xTimerStart(myTimer, 0);
이제 소프트웨어 타이머가 활성화되어 설정한 간격으로 콜백을 실행합니다.
타이머 시작, 중지 및 재설정
FreeRTOS는 타이머를 동적으로 제어할 수 있는 여러 가지 기능을 제공합니다.
| 기능 | 설명 |
| xTimerStart() | 정지된 상태에서 타이머를 시작합니다. |
| xTimerStop() | 실행 중인 타이머를 멈춥니다. |
| xTimerReset() | 타이머의 카운트를 0으로 재설정합니다. |
| xTimerChangePeriod() | 런타임 동안 타이머 기간을 변경합니다. |
| xTimerDelete() | 타이머를 완전히 삭제합니다 |
사용 예:
xTimerStart(myTimer, 0); // Start timer
vTaskDelay(pdMS_TO_TICKS(5000));
xTimerStop(myTimer, 0); // Stop timer after 5s
xTimerReset(myTimer, 0); // Restart timer count
xTimerChangePeriod(myTimer, pdMS_TO_TICKS(2000), 0); // Change to 2s period
이러한 함수는 태스크와 인터럽트 서비스 루틴(ISR) 모두에서 호출할 수 있지만, 인터럽트 루틴 내부에서는 FromISR 버전(예: xTimerStartFromISR())을 사용하십시오.
ESP32의 소프트웨어 타이머에 대한 예제 코드
ESP-IDF 와 FreeRTOS를 사용한 완전한 동작 예제는 다음과 같습니다.
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "driver/gpio.h"
TimerHandle_t myTimer;
#define LED_PIN 2
bool ledLevel = false;
void myTimerCallback(TimerHandle_t xTimer)
{
printf("Timer expired! Callback executed.\n");
ledLevel = !ledLevel;
gpio_set_level(LED_PIN, ledLevel);
}
void app_main(void)
{
gpio_reset_pin(LED_PIN);
gpio_set_direction(LED_PIN, GPIO_MODE_OUTPUT);
myTimer = xTimerCreate("MyTimer", pdMS_TO_TICKS(1000), pdTRUE, 0, myTimerCallback);
if (myTimer == NULL)
{
printf("Timer creation failed!\n");
}
else
{
printf("Starting timer...\n");
xTimerStart(myTimer, 0);
}
}
이 코드는 ESP32에서 FreeRTOS 소프트웨어 타이머를 사용하여 LED를 켜고 끄는 방법을 보여줍니다 .
먼저 GPIO 핀을 LED 출력으로 설정합니다. 그런 다음 1초 간격으로 주기적인 FreeRTOS 타이머를 생성합니다. 타이머가 만료될 때마다 콜백 함수가 자동으로 실행되어 LED 상태를 반전하고 콘솔에 메시지를 출력합니다.
데모: 소프트웨어 타이머를 사용한 ESP32 LED 깜박임
아래 gif는 위 코드의 출력을 보여줍니다.

FreeRTOS 소프트웨어 타이머는 1초마다 만료됩니다. 로그는 콘솔에 출력되고 ESP32에 연결된 LED는 1초마다 깜박입니다.
위에서 볼 수 있듯이 타이머는 1초 마다 만료되어 콜백 함수를 트리거합니다. 콜백이 실행될 때마다 콘솔에 메시지가 출력되고 LED가 같은 간격으로 켜집니다.
타이머 디버깅 및 테스트
소프트웨어 타이머가 예상대로 작동하지 않는 경우 다음을 확인하세요.
1. 스케줄러가 시작되지 않았습니다.
타이머는 vTaskStartScheduler()가 호출된 후에만 작동합니다.
ESP-IDF에서는 app_main()이 실행될 때 스케줄러가 자동으로 시작됩니다.
2. 콜백이 아무것도 출력하지 않습니다.
pdMS_TO_TICKS()를 사용하여 타이머 기간이 올바르게 변환되었는지 확인하십시오.
3. 타이머가 생성되지 않았습니다.
xTimerCreate() 함수가 반환한 핸들이 NULL이 아닌지 항상 확인하십시오.
4. 스택 오버플로 또는 충돌:
콜백 함수가 무거운 작업을 수행하거나 너무 많은 출력을 하는 경우, FreeRTOSConfig.h 파일에서 configTIMER_TASK_STACK_DEPTH 값을 증가시키십시오.
5. 여러 타이머가 서로를 지연시킵니다.
모든 콜백이 단일 타이머 서비스 작업을 공유하므로 느린 콜백 하나가 다른 콜백을 차단할 수 있습니다.
팁: 타이밍 문제가 의심될 경우 vTaskGetRunTimeStats()를 사용하여 타이머 서비스 작업의 CPU 사용량을 확인하세요.
FreeRTOS 작업 알림
작업 알림은 FreeRTOS의 가장 강력하고 가벼운 기능 중 하나입니다. 작업 알림 기능을 사용하면 큐, 세마포어 또는 기타 복잡한 IPC(프로세스 간 통신) 메커니즘을 사용하지 않고도 작업 간에 신호나 작은 데이터 값을 직접 전송할 수 있습니다.
이 섹션에서는 작업 알림이 무엇인지, 작업 알림이 큐와 세마포어보다 많은 경우 더 나은 이유, 그리고 ESP32 FreeRTOS 에서 작업 알림을 효과적으로 사용하는 방법을 알아보겠습니다 .
작업 알림이란 무엇입니까?
FreeRTOS에서 모든 작업은 내부 알림 값 (내장 변수처럼)을 갖습니다. 이 값은 다른 작업이나 인터럽트 서비스 루틴(ISR)에서 설정, 증가 또는 플래그로 사용될 수 있습니다.
각 작업에 대한 개인 사서함 이라고 생각하면 됩니다 .
다른 작업이나 ISR이 알림을 보내면 대상 작업은 다음을 수행할 수 있습니다.
- 알림을 기다리고 있었다면 깨어나세요
- 알림 값을 읽어보세요
- 자동으로 재설정
FreeRTOS는 다음과 같은 다양한 알림 API를 제공합니다.
xTaskNotifyGive()
xTaskNotify()
xTaskNotifyFromISR()
ulTaskNotifyTake()
xTaskNotifyWait()
이를 통해 신호나 작은 정수를 매우 효율적으로 전송할 수 있으며, 큐보다 더 빠르고 가볍습니다 .
큐와 세마포어에 비해 장점
큐와 세마포어가 매우 유용하지만, 간단한 신호 전달이나 이벤트 계산에는 작업 알림이 훨씬 더 효율적입니다 .
작업 알림이 선호되는 이유는 다음과 같습니다.
| 특징 | Queue | Semaphore | Task Notification |
| 메모리 사용량 | 높음(버퍼 필요) | 중간 | 매우 낮음(버퍼 없음) |
| 속도 | 더 느리게 | 보통의 | 가장 빠른 |
| 데이터 유형 | 모든 (구조체, 바이트 등) | 이진법 또는 카운트 | 32비트 정수 |
| 사용 사례 | 데이터 전달 | 동기화 | 신호 및 카운터 |
이벤트가 발생했다는 사실만 작업에 알려야 하는 경우 , 작업 알림을 사용하는 것이 훨씬 간단하고 효율적입니다.
예시 사용 사례:
- 타이머가 만료되면 작업에 알림
- ISR에서 신호 데이터 준비됨
- 버튼 누름 또는 이벤트 계산
작업 알림 보내기 및 받기
ESP-IDF를 사용하여 FreeRTOS에서 알림을 보내고 받는 방법을 살펴보겠습니다.
알림 보내기
작업에서:
xTaskNotifyGive(taskHandle);
ISR에서:
xTaskNotifyGiveFromISR(taskHandle, NULL);
사용자 정의 값이 있는 다른 작업에서:
xTaskNotify(taskHandle, 0x01, eSetValueWithOverwrite);
알림 수신
수신 작업에서:
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
- 첫 번째 매개변수( pdTRUE)는 알림값을 수신한 후 해당 알림값을 지웁니다.
- 두 번째 매개변수는 시간 제한(대기 시간)입니다.
또는 다음을 사용할 수 있습니다.
xTaskNotifyWait(0x00, 0x00, notiificationValue, portMAX_DELAY);
이것은 알림을 기다린 후 수신된 값을 notificationValue에 저장합니다.
작업 알림에 대한 예제 코드
다음은 한 작업이 다른 작업에 알림을 보내는 간단한 ESP32 FreeRTOS 예 입니다.
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
TaskHandle_t Task1Handle;
TaskHandle_t Task2Handle;
void Task1(void *pvParameters)
{
while (1)
{
printf("Task1: Sending notification to Task2\n");
xTaskNotifyGive(Task2Handle);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
void Task2(void *pvParameters)
{
while (1)
{
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
printf("Task2: Notification received!\n");
}
}
void app_main(void)
{
xTaskCreate(Task2, "Task2", 2048, NULL, 2, &Task2Handle);
xTaskCreate(Task1, "Task1", 2048, NULL, 2, &Task1Handle);
}
이 코드는 ESP32에서 FreeRTOS 작업 알림을 사용하여 작업 간 통신을 보여줍니다. Task1은 1초마다 Task2에 알림을 주기적으로 전송합니다. Task2는 알림을 기다리고 수신되면 메시지를 출력합니다. 이 방식을 사용하면 대기열이나 세마포어를 사용하지 않고도 작업이 이벤트를 효율적으로 동기화하거나 신호를 보낼 수 있습니다.
참고: 작업을 생성할 때 알림을 받는 작업이 알림을 보내는 작업보다 먼저 생성되었는지 확인하세요. 보내는 작업이 먼저 실행되면 아직 존재하지 않는 작업에 알림을 보내려고 시도하여 오류가 발생합니다. 또는 보내는 작업의 실행을 지연시켜 받는 작업이 시작할 시간을 줄 수 있습니다.
실행 중 작업 알림
아래 gif는 작업 알림에 대한 위 코드의 출력을 보여줍니다.

FreeRTOS Task2는 Task1에서 알림을 보낼 때만 실행됩니다. 로그는 ESP32 시리얼 콘솔에 출력됩니다.
Task2는 지연이 전혀 없음에도 불구하고 Task1 에서 Notification을 보낼 때만 실행되는 것을 확인할 수 있습니다 . 즉, Task Notification을 사용하여 작업을 동기화할 수 있습니다. 대기열이나 지연 없이 깔끔하고 빠른 통신이 가능합니다.
타이머와 작업 알림 결합
지금까지 FreeRTOS 소프트웨어 타이머와 작업 알림을 각각 사용하는 방법을 알아보았습니다. 이제 두 기능을 결합하여 ESP32 프로젝트의 효율성을 더욱 높이는 방법을 살펴보겠습니다. 타이머는 주기적인 이벤트를 생성하는 데 유용하고, 작업 알림은 작업 신호를 보내는 데 적합합니다. 이 두 기능을 결합하면 지연이나 대기열을 사용하지 않고도 특정 작업을 정기적으로 트리거할 수 있습니다.
타이머를 사용하여 작업 알림
많은 FreeRTOS 애플리케이션에서 작업 만료 시 알림을 제공하는 타이머가 필요할 수 있습니다.
예를 들면 다음과 같습니다.
- 타이머는 1초마다 센서를 읽도록 작업에 알릴 수 있습니다.
- 타이머는 UART나 Wi-Fi를 통해 데이터를 전송하라는 작업을 신호로 보낼 수 있습니다.
- 타이머는 제어 작업에 알림을 보내 LED를 켜고 끌 수 있습니다.
기본적인 아이디어는 다음과 같습니다.
- 소프트웨어 타이머가 주기적으로 실행됩니다.
- 콜백 함수 내부에서 xTaskNotifyGive() 또는 xTaskNotify()를 사용하여 다른 작업에 신호를 보냅니다.
- 작업은 알림을 수신할 때까지 ulTaskNotifyTake()를 사용하여 대기합니다.
- 알림을 받으면 원하는 작업을 수행합니다.
이 방법은 차단되지 않고 가벼우며 실시간 시스템에 적합합니다 .
실제 예 - 타이머와 알림을 사용한 LED 깜박임
다음과 같은 간단한 예를 작성해 보겠습니다.
- 타이머 는 1초마다 작동합니다.
- 작업을 알립니다 .
- 이 작업은 알림을 받을 때마다 LED를 켜고 끕니다 .
예제 코드
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "driver/gpio.h"
#define LED_PIN 2
bool ledLevel = false;
TaskHandle_t ledTaskHandle;
TimerHandle_t timerHandle;
void timerCallback(TimerHandle_t xTimer)
{
// Notify the LED task
xTaskNotifyGive(ledTaskHandle);
}
void ledTask(void *pvParameters)
{
gpio_reset_pin(LED_PIN);
gpio_set_direction(LED_PIN, GPIO_MODE_OUTPUT);
while (1)
{
// Wait until timer notifies
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
// Toggle LED
ledLevel = !ledLevel;
gpio_set_level(LED_PIN, ledLevel);
printf("LED toggled. State: %d\n", ledLevel);
}
}
void app_main(void)
{
printf("FreeRTOS Timer + Task Notification Example\n");
// Create LED Task
xTaskCreate(ledTask, "LED_Task", 2048, NULL, 2, &ledTaskHandle);
// Create Timer (1 second period, auto-reload)
timerHandle = xTimerCreate("LED_Timer", pdMS_TO_TICKS(1000), pdTRUE, NULL, timerCallback);
if (timerHandle != NULL)
{
xTimerStart(timerHandle, 0);
printf("Timer started successfully.\n");
}
else
{
printf("Timer creation failed!\n");
}
}
이 코드는 FreeRTOS 소프트웨어 타이머와 ESP32의 작업 알림을 사용하여 LED를 전환하는 방법을 보여줍니다 .
- 타이머는 1초 간격의 자동 재설정 주기로 생성됩니다.
- 콜백 함수(timerCallback)는 무거운 작업을 수행하지 않으며, 단순히 LED 작업에 알림을 보냅니다.
- LED 작업은 ulTaskNotifyTake()에서 차단된 상태로 유지되며, 알림을 받을 때까지 CPU를 소비하지 않습니다.
- 알림을 받으면 LED를 토글하고 새로운 상태를 출력합니다.
FreeRTOS에서 주기적 작업을 수행하는 데 선호되는 방식입니다 . 지연 대신 타이머와 알림을 사용하는 방식입니다 . 이를 통해 애플리케이션의 응답성, 전력 효율성, 그리고 실시간 보안을 유지할 수 있습니다 .
타이머 + 작업 알림 출력 예제
아래 gif는 타이머 + 작업 알림에 대한 위 코드의 출력을 보여줍니다.

ESP32에 연결된 LED가 1초마다 깜빡입니다. 또한 ledTask의 로그가 콘솔에 출력됩니다.
위에서 볼 수 있듯이, 매초 타이머가 작동하여 LED 작업 에 알림을 보냅니다 . 작업은 즉시 깨어나 LED를 켠 후 다음 알림을 기다립니다.
지연 기능이 사용되지 않습니다. 순전히 이벤트 기반 이어서 효율성이 매우 높습니다.
일반적인 문제 및 문제 해결
ESP32에서 FreeRTOS 소프트웨어 타이머 및 작업 알림을 사용하는 동안 몇 가지 일반적인 문제가 발생할 수 있습니다. 이러한 문제는 대개 잘못된 구성, 함수 호출 누락 또는 FreeRTOS 커널 작동 방식에 대한 오해로 인해 발생합니다.
이 섹션에서는 가장 빈번하게 발생하는 문제 와 그 원인, 그리고 이를 쉽게 해결하는 방법을 살펴보겠습니다 .
타이머가 콜백을 트리거하지 않음
소프트웨어 타이머가 콜백 함수를 호출하지 않는 경우 다음을 확인하세요.
1. 스케줄러가 시작되지 않음
FreeRTOS 타이머는 스케줄러가 활성화된 상태에서만 실행됩니다.
ESP-IDF에서는 app_main()이 시작될 때 vTaskStartScheduler()가 자동으로 호출되지만, 순수 FreeRTOS 환경에서 테스트할 경우 반드시 수동으로 시작해야 합니다.
2. 타이머가 시작되지 않음
xTimerCreate()를 사용하여 타이머를 생성해도 자동으로 시작되지 않습니다.
생성 후 xTimerStart() 또는 xTimerStartFromISR()를 호출해야 합니다. xTimerStart(myTimer, 0);
3. 잘못된 기간 설정:
항상 pdMS_TO_TICKS()를 사용하여 밀리초를 변환하십시오.
예시: pdMS_TO_TICKS(1000) // 1000 밀리초를 틱으로 변환
4. 낮은 틱 속도:
configTICK_RATE_HZ 값이 너무 낮으면(예: 100), 타이머가 지연되는 것처럼 보일 수 있습니다.
밀리초 단위 정확도를 위해 1000으로 증가시키십시오.
5. 타이머가 삭제되었거나 오버플로되었습니다.
실수로 타이머를 삭제하거나 콜백에서 잘못 재설정하지 않았는지 확인하세요.
팁: 콜백 함수에 printf()를 추가하여 호출되고 있는지 확인하세요.
작업이 알림을 받지 못함
작업이 알림을 전혀 받지 못한다면 신호 전달 논리에 문제가 있을 가능성이 높습니다.
다음 사항을 확인하세요.
1. 잘못된 작업 핸들 또는 에서 사용된 작업 핸들이 에서 반환된 핸들과 동일한지
xTaskNotifyGive() 또는 xTaskNotify()에서 사용되는 작업 핸들이 xTaskCreate()에서 반환된 것과 동일한지 확인하십시오.
xTaskCreate(taskFunc, "Task", 2048, NULL, 2, &taskHandle); // 이후: xTaskNotifyGive(taskHandle);
2. 잘못된 대기 기능
작업은 알림을 기다리기 위해 다음 기능 중 하나를 사용해야 합니다.
- ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
- xTaskNotifyWait(0, 0, &value, portMAX_DELAY);
이 중 하나를 사용하는 것을 잊어버리면 해당 작업은 절대로 차단 해제되지 않습니다.
3. 알림 값이 이미 사용됨
새로운 알림이 전송되기 전에 ulTaskNotifyTake()를 여러 번 호출하면 아무것도 수신하지 못합니다.
각 알림이 하나의 Take()에 대응하도록 하십시오.
4. 작업 대기 시작 전 알림 전송
타이머나 다른 작업이 수신 작업이 대기 상태에 들어가기 전에 알림을 전송하면 알림이 손실될 수 있습니다.
모든 작업이 준비된 후에만 이벤트 그룹이나 시작 타이머와 같은 동기화 기법을 사용할 수 있습니다.
스택 크기 및 타이밍 오류
FreeRTOS에서 발생하는 또 다른 일반적인 문제의 원인은 스택 크기가 부족 하거나 타이밍 구성 오류가 있는 것 입니다 .
1. 스택 오버플로우
콜백 또는 태스크에서 printf()와 같은 무거운 함수를 사용하면 스택 오버플로우가 발생할 수 있습니다.
태스크 생성 시 스택 크기를 늘리거나 FreeRTOSConfig.h에서 타이머 태스크 구성을 수정하십시오.
#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE * 2)
2. 콜백 내부에서 호출 차단
타이머 콜백 내부에서 vTaskDelay()와 같은 함수나 긴 루프를 절대 사용하지 마십시오. 타이머 서비스 작업이 정지되어 다른 모든 타이머를 차단하게 됩니다.
3. 여러 타이머 간섭
모든 소프트웨어 타이머는 하나의 서비스 작업을 공유한다는 점을 기억하세요. 하나의 콜백이 너무 오래 걸리면 다른 타이머의 작업이 지연됩니다.
4. 잘못된 틱 구성
FreeRTOS 커널은 시간 측정을 위해 틱(tick)을 사용합니다.
FreeRTOSConfig.h 파일에서 configTICK_RATE_HZ가 올바르게 설정되었는지 확인하십시오. 일반적으로 다음과 같습니다:
#define configTICK_RATE_HZ 1000
5. 워치독 타이머(WDT) 리셋
콜백이 너무 오랫동안 양보 없이 실행되면 ESP32의 워치독 타이머가 리셋을 트리거할 수 있습니다. 콜백은 짧고 효율적으로 작성하세요.
팁: 타이밍 문제를 디버깅할 때는 ESP-IDF 모니터 또는 menuconfig를 사용하여 FreeRTOS 매개변수를 조정하십시오.
결론
ESP32 FreeRTOS 소프트웨어 타이머 및 작업 알림 튜토리얼을 마무리합니다. 이 글에서는 소프트웨어 타이머를 사용하여 주기적 이벤트를 생성하고, 큐나 세마포어 없이도 작업 알림을 사용하여 효율적인 작업 간 통신을 수행하는 방법을 알아보았습니다. 이러한 기법을 통해 애플리케이션의 가벼움과 응답성이 향상되고 ESP32에서 실시간 성능을 구현하는 데 이상적인 환경을 조성할 수 있습니다.
다음으로, 작업 제어: 작업 일시 중지, 재개 및 삭제에 대해 알아보겠습니다 . 이 튜토리얼에서는 작업 실행 흐름을 동적으로 관리하는 방법을 보여줍니다. 필요하지 않을 때는 작업을 일시 중지하고, 필요할 때는 재개하며, 시스템 리소스를 확보하기 위해 안전하게 삭제하는 방법을 소개합니다. 더욱 심층적인 제어 및 최적화 기술을 통해 FreeRTOS에 대한 전문성을 키워나가는 저희의 지속적인 노력에 기대해 주세요.
'ESP32' 카테고리의 다른 글
| ESP-32 LVGL 그래픽을 사용한 고급 기술 - 소개 (0) | 2025.11.24 |
|---|---|
| ESP32 FreeRTOS 구현 살펴보기 (0) | 2025.11.23 |
| ESP32 FreeRTOS 튜토리얼 가이드 6부작 6 (0) | 2025.11.21 |
| FreeRTOS를 사용한 ESP32: 소프트웨어 타이머/타이머 인터럽트 (0) | 2025.11.21 |
| ESP32 ESP-NOW 양방향 커뮤니케이션 (0) | 2025.11.20 |
| esp32 및 esp8266 Dallas ds18b20 네트워크 연결 (0) | 2025.11.19 |
| ESP32 FreeRTOS 튜토리얼 가이드 6부작 4 (1) | 2025.11.19 |
| ESP32 FreeRTOS 튜토리얼 가이드 6부작 3 (0) | 2025.11.19 |
취업, 창업의 막막함, 외주 관리, 제품 부재!
당신의 고민은 무엇입니까? 현실과 동떨어진 교육, 실패만 반복하는 외주 계약,
아이디어는 있지만 구현할 기술이 없는 막막함.
우리는 알고 있습니다. 문제의 원인은 '명확한 학습, 실전 경험과 신뢰할 수 있는 기술력의 부재'에서 시작됩니다.
이제 고민을 멈추고, 캐어랩을 만나세요!
코딩(펌웨어), 전자부품과 디지털 회로설계, PCB 설계 제작, 고객(시장/수출) 발굴과 마케팅 전략으로 당신을 지원합니다.
제품 설계의 고수는 성공이 만든 게 아니라 실패가 만듭니다. 아이디어를 양산 가능한 제품으로!
귀사의 제품을 만드세요. 교육과 개발 실적으로 신뢰할 수 있는 파트너를 확보하세요.
캐어랩