임베디드 시스템에서 여러 작업을 동시에 처리해야 하는 IoT 기기 개발 시, RTOS는 선택이 아닌 필수입니다. 이번 포스팅에서는 STM32와 FreeRTOS(CMSIS-RTOS v2)를 활용하여 온습도 데이터를 수집하고, OLED 출력 및 UART 전송을 동시에 수행하는 실전 프로젝트를 구현해 보겠습니다.

1. 프로젝트 설계: 다중 태스크 및 자원 관리
효율적인 시스템을 위해 기능을 세 개의 독립적인 태스크로 분리하고, 태스크 간 데이터 전달을 위해 큐(Queue)를, 디스플레이 자원 보호를 위해 뮤텍스(Mutex)를 사용합니다.
주요 태스크 정의
- Sensor Task (우선순위: 높음): BME280 센서에서 1초마다 데이터를 읽어 큐에 전달합니다.
- Display Task (우선순위: 보통): 큐에서 데이터를 받아 OLED에 실시간 수치를 출력합니다.
- Communication Task (우선순위: 보통): 큐에서 데이터를 받아 UART로 PC에 전송합니다.
주의: 하나의 큐를 두 태스크(Display, Comm)가 동시에 Get하면 데이터가 한쪽으로만 흘러갑니다. 이를 방지하기 위해 각 태스크 전용 큐를 만들거나, 데이터를 복사해서 전달하는 구조가 안전합니다. 본 예제에서는 가독성을 위해 구조체 포인터 공유 방식을 기준으로 설명합니다.
2. 핵심 코드 구현 (CMSIS-RTOS v2 기준)
2.1 초기화 및 구조체 정의
#include "cmsis_os2.h"
#include "ssd1306.h"
typedef struct {
float temperature;
float humidity;
} SensorData_t;
osMessageQueueId_t sensorQueue;
osMutexId_t displayMutex;
// 큐 및 뮤텍스 생성
sensorQueue = osMessageQueueNew(5, sizeof(SensorData_t), NULL);
displayMutex = osMutexNew(NULL);
2.2 센서 데이터 수집 태스크
void SensorTask(void *argument) {
SensorData_t data;
for (;;) {
data.temperature = BME280_ReadTemperature();
data.humidity = BME280_ReadHumidity();
// 큐로 데이터 전송 (Timeout 0으로 비차단 전송)
osMessageQueuePut(sensorQueue, &data, 0, 0);
osDelay(1000); // 1초 대기
}
}
2.3 OLED 디스력 및 자원 보호
여러 태스크가 I2C 버스를 공유할 때 발생할 수 있는 데이터 충돌을 뮤텍스로 방지합니다.
void DisplayTask(void *argument) {
SensorData_t receivedData;
char str[20];
for (;;) {
if (osMessageQueueGet(sensorQueue, &receivedData, NULL, osWaitForever) == osOK) {
// 뮤텍스 획득: I2C 디스플레이 자원 점유
if (osMutexAcquire(displayMutex, osWaitForever) == osOK) {
sprintf(str, "T: %.1fC", receivedData.temperature);
SSD1306_GotoXY(0, 0);
SSD1306_Puts(str, &Font_11x18, 1);
SSD1306_UpdateScreen();
osMutexRelease(displayMutex); // 뮤텍스 반환
}
}
}
}
3. 시스템 최적화 포인트 (수익화 및 기술 전문성)
구글 검색 상위 노출을 위해 임베디드 개발자가 놓치기 쉬운 최적화 팁을 추가합니다.
- 스택 크기 최적화: printf나 sprintf는 스택을 많이 소모합니다. vTaskList를 활용해 각 태스크의 스택 여유 공간을 확인하고 최적의 크기를 할당하세요.
- 우선순위 상속(Priority Inheritance): 뮤텍스를 사용하면 낮은 우선순위 태스크가 리소스를 잡고 있을 때 높은 우선순위 태스크가 밀리는 현상을 방지할 수 있습니다.
- Tickless Idle 활성화: 배터리 기반 IoT 기기라면 configUSE_TICKLESS_IDLE을 활성화하여 전력 소비를 극적으로 줄여야 합니다.
결론
이번 프로젝트를 통해 FreeRTOS의 핵심 요소인 Task, Queue, Mutex를 실무에 어떻게 적용하는지 살펴보았습니다. RTOS를 활용하면 복잡한 IoT 로직을 구조화된 코드로 관리할 수 있으며, 시스템의 안정성을 크게 높일 수 있습니다.
포스팅이 도움이 되셨다면 공감과 댓글 부탁드립니다! STM32와 FreeRTOS 관련 궁금한 점은 언제든 질문해 주세요.
'Firmware & RTOS > FreeRTOS & Real-time Scheduling' 카테고리의 다른 글
| CMSIS-RTOS v1 vs v2 차이점 완벽 정리: FreeRTOS 마이그레이션 가이드 (0) | 2025.01.18 |
|---|---|
| FreeRTOS 디버깅 가이드: 스택 오버플로우 및 메모리 부족 해결 방법 (0) | 2025.01.18 |
| FreeRTOS 이벤트 그룹(Event Group) 완벽 가이드: 다중 태스크 동기화 (CMSIS-RTOS v2) (0) | 2025.01.17 |
| FreeRTOS 저전력 최적화 가이드: Idle Task와 Tickless Idle 모드 활용법 (0) | 2025.01.16 |
| FreeRTOS 소프트웨어 타이머 완벽 가이드: osTimerNew 사용법 및 예제 (CMSIS-RTOS v2) (0) | 2025.01.15 |