임베디드 시스템에서 효율적인 멀티태스킹 구현은 시스템의 성능과 안정성을 극대화하는 데 필수적입니다. 본 기사에서는 C언어를 사용해 임베디드 환경에서 멀티태스킹을 구현하는 방법을 소개합니다. 기본 개념부터 실무 예제까지 다루며, 실시간 운영체제(RTOS)를 활용해 태스크 관리와 동기화를 효율적으로 수행하는 방법도 설명합니다. 이 기사를 통해 멀티태스킹 기술을 실무에 적용하는 방법을 익힐 수 있습니다.
멀티태스킹의 개념과 필요성
멀티태스킹은 컴퓨터 시스템이 동시에 여러 작업(태스크)을 수행할 수 있도록 하는 개념입니다. 이는 중앙처리장치(CPU)가 작업 간에 빠르게 전환함으로써 이루어지며, 사용자는 모든 작업이 동시에 실행되는 것처럼 느낄 수 있습니다.
임베디드 시스템에서 멀티태스킹의 중요성
임베디드 시스템은 제한된 자원으로 다양한 작업을 수행해야 하며, 멀티태스킹은 다음과 같은 이유로 중요합니다:
- 자원 최적화: 제한된 메모리와 CPU 자원을 효과적으로 활용할 수 있습니다.
- 실시간 응답: 중요한 작업에 우선순위를 부여하여 즉각적인 처리가 가능합니다.
- 복잡한 작업 처리: 데이터 수집, 사용자 인터페이스, 네트워크 통신 등 여러 작업을 병렬적으로 수행할 수 있습니다.
멀티태스킹이 적용되는 주요 사례
- 자동차 시스템: 엔진 제어, 센서 데이터 처리, 사용자 입력 등의 작업 관리
- 스마트 홈 기기: 센서 모니터링, 네트워크 연결, 사용자 제어 처리
- 산업용 로봇: 경로 계산, 센서 데이터 수집, 작업 스케줄링
임베디드 시스템에서 멀티태스킹을 구현하면 다양한 기능을 동시에 처리하면서도 안정성과 성능을 유지할 수 있습니다.
임베디드 시스템에서의 멀티태스킹 구조
임베디드 시스템에서 멀티태스킹을 구현하기 위해서는 여러 구성 요소를 체계적으로 설계해야 합니다. 다음은 멀티태스킹 구조의 핵심 구성 요소입니다.
1. 스케줄러
스케줄러는 시스템에서 실행될 태스크의 순서를 결정하는 역할을 합니다.
- 우선순위 기반 스케줄링: 각 태스크에 우선순위를 부여하고, 우선순위가 높은 태스크를 먼저 실행합니다.
- 라운드 로빈 스케줄링: 모든 태스크에 동일한 시간 슬라이스를 제공하며, 공평한 실행을 보장합니다.
- 실시간 스케줄링: 주기적으로 실행되어야 하는 태스크를 처리하기 위해 주기적 스케줄링을 지원합니다.
2. 태스크
태스크는 시스템에서 수행해야 하는 개별 작업을 나타냅니다.
- 태스크 상태: 태스크는 실행, 준비, 대기 상태를 포함한 여러 상태를 가질 수 있습니다.
- 태스크 컨텍스트: CPU 레지스터, 스택 포인터, 프로그램 카운터 등의 실행 상태를 저장하여 태스크 간 전환을 가능하게 합니다.
3. 태스크 간 통신
멀티태스킹 환경에서는 태스크 간 데이터와 신호를 교환해야 합니다.
- 큐(Message Queue): 데이터를 FIFO(First In, First Out) 방식으로 저장하고 전달합니다.
- 세마포어(Semaphore): 태스크 간 동기화를 위해 사용되며, 공유 자원 접근을 제어합니다.
- 뮤텍스(Mutex): 태스크가 공유 자원에 배타적으로 접근할 수 있도록 보장합니다.
4. 인터럽트
임베디드 시스템에서는 인터럽트를 통해 긴급한 태스크를 즉시 처리할 수 있습니다.
- 하드웨어 인터럽트: 센서나 외부 장치에서 발생하는 이벤트를 처리합니다.
- 소프트웨어 인터럽트: 태스크 간 신호 전달과 스케줄링을 위한 내부 이벤트를 처리합니다.
5. 메모리 관리
멀티태스킹 환경에서는 각 태스크가 독립적으로 실행될 수 있도록 메모리 할당을 효율적으로 관리해야 합니다.
- 스택(Stack): 각 태스크에 별도의 스택을 제공하여 독립적인 함수 호출과 로컬 변수를 처리합니다.
- 힙(Heap): 동적 메모리 할당을 통해 태스크가 필요한 데이터 구조를 생성할 수 있습니다.
이러한 구조를 바탕으로 멀티태스킹을 구현하면, 임베디드 시스템이 동시에 다양한 작업을 안정적으로 수행할 수 있습니다.
C언어로 멀티태스킹을 구현하는 기본 기술
C언어는 임베디드 시스템에서 널리 사용되는 프로그래밍 언어로, 멀티태스킹 구현을 위한 다양한 기술을 제공합니다. 아래는 멀티태스킹을 구현하기 위한 주요 기법입니다.
1. 스레드 생성과 관리
C언어에서 스레드는 멀티태스킹 구현의 기본 단위입니다.
- POSIX 스레드(Pthread): 대부분의 운영체제에서 지원하는 표준 API로, 스레드 생성과 관리를 쉽게 수행할 수 있습니다.
#include <pthread.h>
void* task_function(void* arg) {
// 작업 내용
return NULL;
}
int main() {
pthread_t thread_id;
pthread_create(&thread_id, NULL, task_function, NULL);
pthread_join(thread_id, NULL);
return 0;
}
- 스레드 라이브러리 사용: 특정 플랫폼 전용 라이브러리를 활용해 최적화된 스레드 구현이 가능합니다.
2. 태스크 전환
멀티태스킹에서 중요한 것은 태스크 전환(context switching)입니다.
- 스택과 레지스터 저장: 실행 중인 태스크의 상태를 저장하고, 새로운 태스크의 상태를 복원합니다.
- 인터럽트를 활용한 전환: 타이머 인터럽트를 사용해 정기적으로 태스크를 전환합니다.
3. 인터럽트 기반 작업 분리
인터럽트는 멀티태스킹에서 중요한 역할을 합니다.
- 하드웨어 타이머: 타이머 인터럽트를 설정하여 주기적으로 태스크 스케줄링을 트리거합니다.
void timer_interrupt_handler() {
// 현재 태스크 상태 저장
// 다음 태스크 상태 복원
}
4. 기본 스케줄링 구현
C언어로 간단한 라운드 로빈 스케줄러를 구현할 수 있습니다.
- 라운드 로빈 방식: 모든 태스크를 순서대로 실행하며, 일정 시간 동안 실행한 후 다음 태스크로 전환합니다.
void schedule_tasks() {
while (1) {
for (int i = 0; i < num_tasks; i++) {
if (tasks[i].state == READY) {
tasks[i].execute();
}
}
}
}
5. 메모리 관리
멀티태스킹 환경에서는 각 태스크에 독립적인 메모리 공간을 할당해야 합니다.
- 스택 공간 분리: 각 태스크에 고유의 스택을 설정합니다.
- 동적 메모리 사용:
malloc
과 같은 동적 메모리 할당을 통해 필요에 따라 메모리를 관리합니다.
C언어의 이러한 기술을 조합하면, 임베디드 시스템에서 효율적이고 안정적인 멀티태스킹 구현이 가능합니다.
실시간 운영체제(RTOS)의 역할과 활용
실시간 운영체제(Real-Time Operating System, RTOS)는 임베디드 시스템에서 멀티태스킹을 간소화하고 효율적으로 관리하기 위한 핵심 도구입니다. RTOS를 사용하면 태스크 스케줄링, 동기화, 메모리 관리 등 복잡한 작업을 쉽게 처리할 수 있습니다.
1. RTOS의 주요 역할
- 스케줄링: RTOS는 태스크의 우선순위를 기반으로 실행 순서를 자동으로 관리합니다.
- 태스크 관리: 태스크 생성, 삭제, 상태 전환 등의 작업을 간단한 API로 처리할 수 있습니다.
- 태스크 동기화: 세마포어, 뮤텍스, 큐 등을 제공하여 태스크 간의 협업을 지원합니다.
- 시간 제어: 실시간 작업의 주기를 정확히 제어할 수 있습니다.
2. 대표적인 RTOS 예시
- FreeRTOS: 오픈소스 기반 RTOS로, 경량화와 유연성이 뛰어나 많은 임베디드 프로젝트에서 사용됩니다.
- Zephyr: 모듈식 구조를 가진 RTOS로, 다양한 하드웨어 플랫폼에서 실행 가능합니다.
- ThreadX: 상용 RTOS로, 성능과 안정성이 입증된 제품입니다.
3. FreeRTOS를 활용한 멀티태스킹
FreeRTOS는 C언어 기반으로 설계되어 있으며, 다음과 같은 방식으로 멀티태스킹을 구현할 수 있습니다.
- 태스크 생성
void vTask1(void *pvParameters) {
while (1) {
// 태스크 1 작업
}
}
void vTask2(void *pvParameters) {
while (1) {
// 태스크 2 작업
}
}
int main() {
xTaskCreate(vTask1, "Task1", 1000, NULL, 1, NULL);
xTaskCreate(vTask2, "Task2", 1000, NULL, 2, NULL);
vTaskStartScheduler(); // 스케줄러 시작
return 0;
}
- 태스크 우선순위
우선순위는 태스크 실행 순서를 결정하며, 숫자가 클수록 높은 우선순위를 가집니다.
4. RTOS 활용의 장점
- 개발 간소화: RTOS는 복잡한 멀티태스킹 구현을 위한 다양한 기능을 제공하여 개발을 단순화합니다.
- 확장성: 새로운 태스크 추가나 하드웨어 변경이 용이합니다.
- 실시간 처리: 실시간 제약 조건을 만족시키며 안정적인 시스템 동작을 보장합니다.
5. RTOS 도입 시의 고려사항
- 시스템 자원: RTOS는 일정한 메모리와 CPU 자원을 요구하므로, 시스템의 자원 제한을 고려해야 합니다.
- 복잡성 증가: RTOS 학습 및 설정에는 시간이 필요합니다.
- 라이센스: 상용 RTOS를 사용하는 경우 라이센스 비용을 검토해야 합니다.
RTOS를 활용하면 임베디드 시스템에서 멀티태스킹 구현이 더욱 효과적이고 안정적으로 이루어질 수 있습니다.
태스크 간 통신 및 동기화
멀티태스킹 환경에서는 태스크 간 데이터 교환과 동기화가 필수적입니다. 이를 효율적으로 처리하기 위해 세마포어, 뮤텍스, 메시지 큐와 같은 기법이 사용됩니다.
1. 세마포어(Semaphore)
세마포어는 공유 자원의 접근을 제어하기 위해 사용됩니다.
- 이진 세마포어(Binary Semaphore): 자원이 하나일 때 사용되며, 값이 0과 1만 가능합니다.
- 카운팅 세마포어(Counting Semaphore): 자원이 여러 개일 때 사용되며, 특정 값까지 증가할 수 있습니다.
SemaphoreHandle_t xSemaphore = xSemaphoreCreateBinary();
if (xSemaphore != NULL) {
if (xSemaphoreTake(xSemaphore, portMAX_DELAY)) {
// 자원 사용
xSemaphoreGive(xSemaphore); // 자원 반환
}
}
2. 뮤텍스(Mutex)
뮤텍스는 한 번에 하나의 태스크만 자원에 접근하도록 보장합니다.
- 우선순위 역전 방지: RTOS의 뮤텍스는 우선순위 상속 메커니즘을 통해 우선순위 역전을 방지합니다.
MutexHandle_t xMutex = xSemaphoreCreateMutex();
if (xMutex != NULL) {
if (xSemaphoreTake(xMutex, portMAX_DELAY)) {
// 자원 사용
xSemaphoreGive(xMutex); // 자원 반환
}
}
3. 메시지 큐(Message Queue)
메시지 큐는 태스크 간 데이터 교환에 사용되며, FIFO(First In, First Out) 방식으로 작동합니다.
- 데이터 교환: 프로듀서 태스크가 데이터를 큐에 넣고, 소비자 태스크가 큐에서 데이터를 꺼냅니다.
QueueHandle_t xQueue = xQueueCreate(10, sizeof(int));
if (xQueue != NULL) {
int value = 42;
xQueueSend(xQueue, &value, portMAX_DELAY); // 큐에 데이터 추가
xQueueReceive(xQueue, &value, portMAX_DELAY); // 큐에서 데이터 가져오기
}
4. 이벤트 그룹(Event Group)
이벤트 그룹은 여러 태스크가 특정 이벤트를 기다리거나 이벤트를 트리거하는 데 사용됩니다.
- 비트 필드: 각 비트가 개별 이벤트를 나타내며, 여러 이벤트를 동시에 처리할 수 있습니다.
EventGroupHandle_t xEventGroup = xEventGroupCreate();
xEventGroupSetBits(xEventGroup, BIT_0); // 이벤트 트리거
xEventGroupWaitBits(xEventGroup, BIT_0, pdTRUE, pdFALSE, portMAX_DELAY); // 이벤트 대기
5. 동기화 설계 시의 고려사항
- 데드락 방지: 두 태스크가 서로 자원을 기다리면서 멈추지 않도록 설계합니다.
- 우선순위 역전 해결: 뮤텍스를 사용해 높은 우선순위 태스크의 대기 시간을 줄입니다.
- 큐 크기 최적화: 큐 크기를 적절히 설정해 메모리 낭비를 방지합니다.
효율적인 태스크 간 통신과 동기화는 멀티태스킹 시스템의 성능과 안정성을 보장하는 핵심 요소입니다.
예제: FreeRTOS를 이용한 멀티태스킹 구현
FreeRTOS는 멀티태스킹을 간단하게 구현할 수 있도록 다양한 기능을 제공합니다. 이번 섹션에서는 FreeRTOS를 활용해 두 개의 태스크를 생성하고, 이 태스크가 주기적으로 작업을 수행하는 예제를 소개합니다.
1. 환경 설정
FreeRTOS 프로젝트를 시작하려면 다음과 같은 준비가 필요합니다.
- 툴체인: GCC, Keil, IAR 등 임베디드 개발용 컴파일러
- FreeRTOS 소스코드: 공식 사이트에서 다운로드
- 하드웨어 플랫폼: STM32, ESP32 등 지원되는 마이크로컨트롤러
2. 태스크 생성
다음 코드는 두 개의 태스크(Task1과 Task2)를 생성하고 실행하는 방법을 보여줍니다.
#include <FreeRTOS.h>
#include <task.h>
// Task 1 함수
void vTask1(void *pvParameters) {
while (1) {
printf("Task 1 is running\n");
vTaskDelay(pdMS_TO_TICKS(1000)); // 1초 대기
}
}
// Task 2 함수
void vTask2(void *pvParameters) {
while (1) {
printf("Task 2 is running\n");
vTaskDelay(pdMS_TO_TICKS(500)); // 0.5초 대기
}
}
int main() {
// 태스크 생성
xTaskCreate(vTask1, "Task1", 1000, NULL, 1, NULL);
xTaskCreate(vTask2, "Task2", 1000, NULL, 2, NULL);
// 스케줄러 시작
vTaskStartScheduler();
// 실행되지 않음
for (;;) {}
}
3. 코드 설명
- 태스크 생성:
xTaskCreate
를 사용해 태스크를 생성합니다. 각 태스크는 함수 포인터, 이름, 스택 크기, 우선순위를 매개변수로 받습니다. - 태스크 실행:
vTaskStartScheduler
를 호출하면 스케줄러가 실행되고 태스크들이 실행됩니다. - 딜레이 사용:
vTaskDelay
는 지정된 시간 동안 태스크 실행을 멈추고 다른 태스크로 전환됩니다.
4. 태스크 간 동기화
세마포어를 사용하여 두 태스크가 공유 자원에 접근하지 않도록 동기화할 수 있습니다.
SemaphoreHandle_t xSemaphore;
void vTask1(void *pvParameters) {
while (1) {
if (xSemaphoreTake(xSemaphore, portMAX_DELAY)) {
printf("Task 1 is accessing the resource\n");
vTaskDelay(pdMS_TO_TICKS(1000));
xSemaphoreGive(xSemaphore);
}
}
}
void vTask2(void *pvParameters) {
while (1) {
if (xSemaphoreTake(xSemaphore, portMAX_DELAY)) {
printf("Task 2 is accessing the resource\n");
vTaskDelay(pdMS_TO_TICKS(500));
xSemaphoreGive(xSemaphore);
}
}
}
int main() {
xSemaphore = xSemaphoreCreateBinary();
xSemaphoreGive(xSemaphore); // 초기 상태 설정
xTaskCreate(vTask1, "Task1", 1000, NULL, 1, NULL);
xTaskCreate(vTask2, "Task2", 1000, NULL, 2, NULL);
vTaskStartScheduler();
for (;;) {}
}
5. 결과
- 두 태스크가 주기적으로 실행되며, 세마포어를 사용해 충돌 없이 자원을 공유합니다.
- 스케줄러는 각 태스크의 우선순위와 딜레이에 따라 태스크를 전환합니다.
6. 확장 가능성
- 추가 태스크 생성: 새로운 태스크를 추가해 복잡한 작업을 분리할 수 있습니다.
- 하드웨어 제어: GPIO, 센서 데이터 처리, 통신 인터페이스와의 연동을 통해 실시간 시스템을 구축할 수 있습니다.
이 예제를 통해 FreeRTOS를 활용한 기본 멀티태스킹 개념과 태스크 간 동기화를 실습할 수 있습니다.
멀티태스킹 구현 시의 주의 사항
멀티태스킹은 시스템 성능을 극대화할 수 있는 강력한 기술이지만, 잘못 구현하면 안정성과 효율성을 저하시킬 수 있습니다. 아래는 멀티태스킹 구현 시 반드시 고려해야 할 주요 사항들입니다.
1. 데드락 방지
데드락은 두 개 이상의 태스크가 서로의 자원을 기다리면서 영원히 멈추는 상태를 말합니다. 이를 방지하기 위한 방법은 다음과 같습니다:
- 자원 요청 순서 정하기: 모든 태스크가 자원을 요청할 때 동일한 순서를 따르도록 설계합니다.
- 타임아웃 사용: 자원 요청 시 타임아웃을 설정하여 데드락 발생 가능성을 줄입니다.
if (xSemaphoreTake(xSemaphore, pdMS_TO_TICKS(1000))) {
// 자원 사용
xSemaphoreGive(xSemaphore);
} else {
// 타임아웃 처리
}
2. 우선순위 역전 해결
우선순위 역전은 낮은 우선순위 태스크가 자원을 점유하면서 높은 우선순위 태스크가 대기하는 상황을 의미합니다. 이를 방지하기 위해 다음을 고려합니다:
- 뮤텍스 사용: RTOS에서 제공하는 우선순위 상속 메커니즘이 적용된 뮤텍스를 사용합니다.
- 적절한 우선순위 설정: 태스크 간 의존성을 분석하여 우선순위를 적절히 설정합니다.
3. 스택 오버플로우 방지
각 태스크에 할당된 스택 크기를 초과하면 스택 오버플로우가 발생하여 시스템이 불안정해질 수 있습니다.
- 스택 크기 확인: 태스크 생성 시 충분한 스택 크기를 설정합니다.
- 스택 사용량 모니터링: FreeRTOS의
uxTaskGetStackHighWaterMark
를 사용해 남은 스택 크기를 확인합니다.
UBaseType_t uxHighWaterMark = uxTaskGetStackHighWaterMark(NULL);
printf("Remaining stack: %d bytes\n", uxHighWaterMark);
4. 공유 자원의 보호
멀티태스킹 환경에서 태스크가 동일한 자원에 접근하면 데이터 손상이나 동작 오류가 발생할 수 있습니다.
- 임계 구역 설정: 중요한 코드 영역은 세마포어나 뮤텍스로 보호합니다.
- 원자적 연산 사용: 공유 데이터 변경 시 가능한 원자적 연산을 활용합니다.
5. 태스크 전환 비용 최소화
태스크 전환은 CPU와 메모리 리소스를 소비하므로, 과도한 전환은 성능 저하를 유발합니다.
- 태스크 수 제한: 필요한 최소한의 태스크만 생성합니다.
- 작업 주기 최적화: 작업 주기를 분석하여 태스크 실행 빈도를 조정합니다.
6. 시스템 성능 모니터링
멀티태스킹 시스템의 성능을 정기적으로 점검하여 병목현상을 방지합니다.
- CPU 사용률 측정: RTOS에서 제공하는 API를 활용해 각 태스크의 실행 시간을 측정합니다.
- 디버깅 툴 사용: Tracealyzer, FreeRTOS+Trace와 같은 도구를 사용해 태스크 동작을 시각화하고 문제를 분석합니다.
7. 코드 유지보수성 확보
복잡한 멀티태스킹 코드는 유지보수가 어려울 수 있으므로, 가독성과 재사용성을 고려한 설계가 필요합니다.
- 모듈화: 각 태스크의 기능을 독립적인 모듈로 분리합니다.
- 주석과 문서화: 태스크 간 상호작용을 명확히 설명하는 주석과 문서를 작성합니다.
이와 같은 주의 사항을 준수하면 멀티태스킹 시스템의 안정성과 성능을 크게 향상시킬 수 있습니다.
응용 예제: 간단한 임베디드 프로젝트
이번 섹션에서는 멀티태스킹을 활용하여 임베디드 환경에서 간단한 프로젝트를 구현하는 예제를 소개합니다. 이 프로젝트는 LED 깜박임과 버튼 입력 처리를 동시에 수행하는 시스템입니다.
1. 프로젝트 개요
- 목표:
- LED를 1초 간격으로 깜박이도록 구현
- 버튼 입력을 처리하여 LED 상태를 토글
- 하드웨어 요구사항:
- LED 연결 핀
- 버튼 입력 핀
- 소프트웨어 구성:
FreeRTOS를 사용하여 두 개의 태스크(Task1: LED 제어, Task2: 버튼 입력 처리)를 생성
2. 시스템 설계
- 태스크 구성:
- Task1 (LED Task): 주기적으로 LED를 On/Off
- Task2 (Button Task): 버튼 상태를 읽고 LED 동작 상태 변경
- 통신 방법:
버튼 입력 처리 결과는 글로벌 변수 또는 메시지 큐를 통해 LED 태스크로 전달
3. 코드 구현
#include <FreeRTOS.h>
#include <task.h>
#include <semphr.h>
// 핀 정의 (예: Arduino 기반)
#define LED_PIN 13
#define BUTTON_PIN 12
// 세마포어 선언
SemaphoreHandle_t xButtonSemaphore;
// LED 제어 태스크
void vLedTask(void *pvParameters) {
bool ledState = false;
while (1) {
// LED 상태 변경
ledState = !ledState;
digitalWrite(LED_PIN, ledState);
printf("LED is %s\n", ledState ? "ON" : "OFF");
// 1초 대기
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
// 버튼 입력 처리 태스크
void vButtonTask(void *pvParameters) {
while (1) {
// 버튼이 눌리면 세마포어 트리거
if (digitalRead(BUTTON_PIN) == LOW) {
xSemaphoreGive(xButtonSemaphore);
vTaskDelay(pdMS_TO_TICKS(200)); // 디바운싱 처리
}
}
}
// LED 상태 제어 태스크
void vControlTask(void *pvParameters) {
while (1) {
// 세마포어 대기
if (xSemaphoreTake(xButtonSemaphore, portMAX_DELAY)) {
printf("Button Pressed: Toggling LED Task\n");
// LED 태스크 상태 제어 (예: 추가 기능 구현)
}
}
}
void setup() {
// 핀 모드 설정
pinMode(LED_PIN, OUTPUT);
pinMode(BUTTON_PIN, INPUT_PULLUP);
// 세마포어 생성
xButtonSemaphore = xSemaphoreCreateBinary();
// 태스크 생성
xTaskCreate(vLedTask, "LED Task", 1000, NULL, 1, NULL);
xTaskCreate(vButtonTask, "Button Task", 1000, NULL, 2, NULL);
xTaskCreate(vControlTask, "Control Task", 1000, NULL, 3, NULL);
// 스케줄러 시작
vTaskStartScheduler();
}
void loop() {
// FreeRTOS 스케줄러가 실행되므로 이 함수는 사용되지 않음
}
4. 코드 설명
- vLedTask: 1초 주기로 LED를 깜박이도록 설정
- vButtonTask: 버튼 입력 상태를 읽고, 세마포어를 통해 LED 상태를 제어
- vControlTask: 버튼 입력 이벤트에 반응하여 추가 동작 수행
5. 결과
- LED Task: 주기적으로 LED 깜박임
- Button Task: 버튼 입력을 감지하여 LED 상태 변경
- Control Task: 버튼 이벤트에 따라 추가 기능을 구현 가능
6. 확장 가능성
- 센서 추가: 온도 센서나 초음파 센서를 추가해 멀티태스킹 응용 범위 확장
- 통신 기능: UART, SPI, I2C를 통해 외부 장치와 데이터 교환
이 프로젝트는 멀티태스킹 개념을 활용해 간단하지만 실용적인 시스템을 구현하는 데 유용한 예제입니다.
요약
이번 기사에서는 C언어와 FreeRTOS를 활용한 멀티태스킹 구현 방법을 다뤘습니다. 멀티태스킹의 개념과 필요성, 임베디드 시스템에서의 구조, 태스크 간 동기화 기술, 그리고 실질적인 예제를 통해 멀티태스킹의 구현과 주의 사항을 이해할 수 있었습니다. LED 깜박임과 버튼 입력 처리 예제는 멀티태스킹의 실제 응용을 보여주며, 이를 기반으로 복잡한 임베디드 시스템 개발에 활용할 수 있습니다.