반응형
FreeRTOS는 임베디드 시스템에서 태스크 간 통신을 효율적으로 처리하기 위해 다양한 데이터 구조를 제공합니다. 그중 큐(Queue)는 태스크 간 데이터를 주고받는 데 매우 유용하게 활용됩니다. 오늘은 FreeRTOS(CMSIS v1)에서 제공하는 큐의 개념과 활용 방법을 소개하고, 이를 활용한 간단한 예제를 구현해 보겠습니다.
큐(Queue)란 무엇인가?
큐는 데이터 항목을 순서대로 저장하고 관리하는 자료 구조입니다. FIFO(First In First Out) 방식으로 동작하며, 먼저 삽입된 데이터가 가장 먼저 추출됩니다.
FreeRTOS에서 큐는 다음과 같은 경우에 사용됩니다:
- 태스크 간 데이터 전송: 데이터를 생성하는 태스크와 이를 처리하는 태스크 간의 통신.
- 인터럽트와 태스크 간 통신: 인터럽트에서 생성된 데이터를 태스크로 전달.
- 이벤트 신호: 상태 변화나 이벤트 알림을 다른 태스크에 전달.
큐의 특징
- 제한된 크기의 버퍼를 가지며, 메모리가 가득 차면 더 이상 데이터를 삽입할 수 없습니다.
- FreeRTOS에서는
osMessageQueuePut()
함수로 데이터를 큐에 추가하고,osMessageQueueGet()
함수로 데이터를 큐에서 가져옵니다.
osMessageQueuePut()와 osMessageQueueGet() 함수 사용법
osMessageQueuePut()
큐에 데이터를 삽입하는 함수입니다.
osStatus_t osMessageQueuePut(osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout);
주요 매개변수
- mq_id: 큐의 ID.
- msg_ptr: 큐에 삽입할 데이터의 포인터.
- msg_prio: 메시지 우선순위 (CMSIS v1에서는 기본적으로 0).
- timeout: 큐가 가득 찬 경우 대기할 시간.
osMessageQueueGet()
큐에서 데이터를 읽어오는 함수입니다.
osStatus_t osMessageQueueGet(osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout);
주요 매개변수
- mq_id: 큐의 ID.
- msg_ptr: 큐에서 읽어온 데이터를 저장할 포인터.
- msg_prio: 메시지 우선순위 포인터 (NULL로 설정 가능).
- timeout: 큐에 데이터가 없는 경우 대기할 시간.
태스크 간 데이터 교환 예제
예제 시나리오
- 센서 데이터 읽기 태스크: 센서에서 데이터를 읽어 큐에 저장.
- 데이터 처리 태스크: 큐에서 데이터를 읽어와 처리.
코드 구현
헤더 파일 및 초기화
#include "cmsis_os2.h"
#include <stdio.h>
#define QUEUE_SIZE 5
osMessageQueueId_t messageQueue;
센서 데이터 읽기 태스크
void SensorTask(void *argument) {
uint32_t sensorData = 0;
while (1) {
sensorData = ReadSensor(); // 센서 데이터를 읽는 가상 함수
if (osMessageQueuePut(messageQueue, &sensorData, 0, 0) == osOK) {
printf("SensorTask: Data %lu sent to queue.\n", sensorData);
} else {
printf("SensorTask: Failed to send data to queue.\n");
}
osDelay(1000); // 1초 대기
}
}
데이터 처리 태스크
void ProcessTask(void *argument) {
uint32_t receivedData;
while (1) {
if (osMessageQueueGet(messageQueue, &receivedData, NULL, osWaitForever) == osOK) {
printf("ProcessTask: Data %lu received from queue.\n", receivedData);
ProcessData(receivedData); // 데이터를 처리하는 가상 함수
} else {
printf("ProcessTask: Failed to receive data from queue.\n");
}
}
}
큐 생성 및 태스크 시작
int main(void) {
osKernelInitialize();
// 큐 생성
messageQueue = osMessageQueueNew(QUEUE_SIZE, sizeof(uint32_t), NULL);
if (messageQueue == NULL) {
printf("Failed to create message queue.\n");
return -1;
}
// 태스크 생성
osThreadNew(SensorTask, NULL, NULL);
osThreadNew(ProcessTask, NULL, NULL);
osKernelStart();
while (1);
}
실행 결과
시뮬레이션 환경에서 위 코드를 실행하면 다음과 같은 로그를 볼 수 있습니다:
SensorTask: Data 123 sent to queue.
ProcessTask: Data 123 received from queue.
SensorTask: Data 456 sent to queue.
ProcessTask: Data 456 received from queue.
...
센서 데이터가 성공적으로 큐를 통해 전달되고, 처리 태스크에서 해당 데이터를 읽어와 처리하는 것을 확인할 수 있습니다.
큐 활용 사례
- 센서 네트워크: 여러 센서에서 데이터를 수집하고 이를 처리 태스크로 전달.
- 로그 시스템: 태스크에서 생성된 로그 메시지를 큐에 저장하고, 이를 출력 태스크에서 처리.
- 제어 시스템: 이벤트 발생 시 다른 태스크로 신호를 전달하여 제어 흐름을 관리.
FreeRTOS의 큐는 태스크 간 효율적인 데이터 교환을 가능하게 하며, 다양한 임베디드 애플리케이션에서 활용할 수 있습니다. 이 글에서는 기본적인 큐 사용법과 예제를 살펴보았으며, 이를 바탕으로 복잡한 시스템을 설계하는 데 활용할 수 있을 것입니다.
반응형
'FreeRTOS' 카테고리의 다른 글
FreeRTOS 타이머와 시간 관리 (0) | 2025.01.15 |
---|---|
FreeRTOS Semaphore와 Mutex 활용하기 (0) | 2025.01.14 |
FreeRTOS Task (0) | 2025.01.12 |
FreeRTOS 기본 개념과 구현 방법 (0) | 2025.01.11 |
FreeRTOS 개발 환경 설정 및 구현 방법 (0) | 2025.01.10 |