반응형
FreeRTOS는 실시간 운영체제(RTOS)로서, 임베디드 시스템 개발자들에게 효율적인 태스크 관리와 자원 제어를 제공합니다. 이번 포스팅에서는 FreeRTOS를 활용한 간단한 IoT 프로젝트를 구현해보겠습니다. 프로젝트는 온도 및 습도 센서 데이터 수집 및 전송, OLED 디스플레이 제어, 태스크 및 자원 관리 최적화를 중심으로 구성됩니다.
프로젝트 목표
- 온도 및 습도 센서 데이터 수집 및 전송: 센서를 통해 데이터를 읽고 이를 UART 또는 BLE를 통해 전송합니다.
- OLED 디스플레이 제어: 수집된 데이터를 OLED 디스플레이에 출력합니다.
- 태스크 및 자원 관리 최적화: FreeRTOS의 태스크 우선순위, 큐, 세마포어 등을 활용해 시스템 성능을 최적화합니다.
프로젝트 준비물
- MCU: STM32F429ZI 또는 유사 마이크로컨트롤러
- 온습도 센서: DHT22 또는 BME280
- 디스플레이: SSD1306 기반 OLED 디스플레이
- 개발 환경: STM32CubeIDE
- 라이브러리: FreeRTOS CMSIS v1, HAL 라이브러리
프로젝트 설계
주요 태스크 정의
- Sensor Task: 온습도 데이터를 주기적으로 읽어와 큐에 저장합니다.
- Display Task: 큐에서 데이터를 읽어와 OLED 디스플레이에 출력합니다.
- Communication Task: 큐에서 데이터를 읽어와 UART 또는 BLE로 전송합니다.
시스템 구조도
+-------------------+
| Sensor Task |
| 센서 데이터 수집 |
+-------------------+
|
V
+-------------------+
| Queue |
| 센서 데이터 저장 |
+-------------------+
| |
V V
+-------------------+ +-------------------+
| Display Task | | Communication Task|
| 데이터 출력 | | 데이터 전송 |
+-------------------+ +-------------------+
주요 FreeRTOS 개념 활용
- 태스크 우선순위: Sensor Task > Display Task > Communication Task
- 큐: 태스크 간 데이터 교환
- 세마포어: OLED 디스플레이와 UART 자원 보호
코드 구현
1. 프로젝트 초기화
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#include "stm32f4xx_hal.h"
#include "ssd1306.h"
#include "bme280.h"
#define QUEUE_LENGTH 5
#define QUEUE_ITEM_SIZE sizeof(SensorData)
typedef struct {
float temperature;
float humidity;
} SensorData;
QueueHandle_t sensorQueue;
SemaphoreHandle_t displaySemaphore;
void SystemClock_Config(void);
void MX_GPIO_Init(void);
void MX_I2C1_Init(void);
void MX_USART2_UART_Init(void);
2. 태스크 구현
Sensor Task
void SensorTask(void *pvParameters) {
SensorData data;
while (1) {
// 센서 데이터 읽기
data.temperature = BME280_ReadTemperature();
data.humidity = BME280_ReadHumidity();
// 큐에 데이터 저장
xQueueSend(sensorQueue, &data, portMAX_DELAY);
// 1초 대기
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
Display Task
void DisplayTask(void *pvParameters) {
SensorData data;
char buffer[32];
while (1) {
// 큐에서 데이터 수신
if (xQueueReceive(sensorQueue, &data, portMAX_DELAY) == pdPASS) {
// 세마포어 획득
if (xSemaphoreTake(displaySemaphore, portMAX_DELAY) == pdPASS) {
// OLED 디스플레이 업데이트
snprintf(buffer, sizeof(buffer), "Temp: %.2f C", data.temperature);
SSD1306_WriteString(0, 0, buffer);
snprintf(buffer, sizeof(buffer), "Hum: %.2f %%", data.humidity);
SSD1306_WriteString(0, 10, buffer);
SSD1306_UpdateScreen();
// 세마포어 반환
xSemaphoreGive(displaySemaphore);
}
}
// 500ms 대기
vTaskDelay(pdMS_TO_TICKS(500));
}
}
Communication Task
void CommunicationTask(void *pvParameters) {
SensorData data;
char buffer[64];
while (1) {
// 큐에서 데이터 수신
if (xQueueReceive(sensorQueue, &data, portMAX_DELAY) == pdPASS) {
// 데이터 UART로 전송
snprintf(buffer, sizeof(buffer), "Temp: %.2f C, Hum: %.2f %%\r\n", data.temperature, data.humidity);
HAL_UART_Transmit(&huart2, (uint8_t *)buffer, strlen(buffer), HAL_MAX_DELAY);
}
// 1초 대기
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
3. 메인 함수
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_I2C1_Init();
MX_USART2_UART_Init();
// 큐와 세마포어 생성
sensorQueue = xQueueCreate(QUEUE_LENGTH, QUEUE_ITEM_SIZE);
displaySemaphore = xSemaphoreCreateMutex();
// 태스크 생성
xTaskCreate(SensorTask, "SensorTask", 128, NULL, 2, NULL);
xTaskCreate(DisplayTask, "DisplayTask", 128, NULL, 1, NULL);
xTaskCreate(CommunicationTask, "CommTask", 128, NULL, 1, NULL);
// 스케줄러 시작
vTaskStartScheduler();
while (1) {}
}
실행 결과
- OLED 디스플레이: 온도와 습도 데이터를 주기적으로 업데이트
- UART 터미널 출력: 센서 데이터를 텍스트 형식으로 출력
프로젝트 최적화
- 태스크 우선순위 조정: Sensor Task를 최우선으로 설정
- 큐 길이 조정: 데이터 손실 방지를 위해 충분한 큐 크기 확보
- 전력 관리: 저전력 모드 활성화로 에너지 절약
결론
이번 프로젝트를 통해 FreeRTOS를 활용한 IoT 시스템 구현의 기초를 배웠습니다. 태스크, 큐, 세마포어를 조합해 효과적인 태스크 관리와 자원 활용이 가능함을 확인했습니다. 이를 바탕으로 더 복잡한 IoT 프로젝트를 설계해보세요!
반응형
'FreeRTOS' 카테고리의 다른 글
FreeRTOS와 CMSIS-RTOS v1 비교 및 활용 방법 (0) | 2025.01.18 |
---|---|
FreeRTOS 디버깅 및 문제 해결 (0) | 2025.01.18 |
FreeRTOS 이벤트 그룹[ Event Group ] 사용 방법 (0) | 2025.01.17 |
FreeRTOS Idle Task와 Power Management (0) | 2025.01.16 |
FreeRTOS 타이머와 시간 관리 (0) | 2025.01.15 |