이번엔 RTOS에 대해 알아보고 간단한 실습을 해보겠다.
먼저 RTOS란 무엇인가?
Real Time Operating System라고 하며 실시간 운영체제 라고 말한다.
제한된 시간내에 원하는 작업을 모두 처리하는 것을 보장하는 운영체제이다.
여기서 FreeRTOS를 실습할건데 왜 앞에 Free가 붙었나?라고 말한다면 누구나 사용가능하고, 상업적으로 사용해도 비용 청구가 없는 무료이기 때문에 Free가 붙었다.
여기서 선점형과 비선점형이 나오는데 이는 운영체제에 대해 알면 알것이다.
선점형 | 하나의 프로세스가 다른 프로세스 대신에 프로세서를 차지할 수 있다. |
비선점형 | 하나의 프로세스가 끝나지 않으면 다른 프로세스는 프로세서를 차지할 수 없다. |
제공되는 API는 다음과 같다.
종류 | 설명 |
xTaskCreate() | Task 생성 |
vTaskDelete() | Task 삭제 |
vTaskDelay() | 주어진 Clock tick 동안 지연시킴 |
uxTaskTriorityGet() | Task의 우선순위를 돌려줌 |
vTaskProoritySet() | Task의 우선순위를 지정 |
vTaskSuspend() | Task 중지 |
vTaskResume() | 중지된 Task를 다시 시작 |
vTaskResumeFromISR() | Suspend된 Task를 다시 시작 (인터럽트) |
이제 FreeRTOS Task로 LED Blinking 해보자
실습 예제는 FreeRTOS환경을 만들고 Task에서 200ms 주기로 LED를 On/Off하는 프로그램을 작성하는 것이다.
UML은 다음과 같다.
그리고 다음과 같이 칩을 설정해줘라
중간에 주의가 뜨긴하는데 FreeRTOS는 SysTick를 FreeRTOS의 시스템 틱으로도 사용되어서 HAL Timebase를 다른 타이머로 설정하는게 좋다는 의미이다.
또하나의 주의사항은 USE_NEWLIB_REENTRANT 활성화인데, 이것을 활성화하는 하라는 이유는 여러 태스크가 동작함으로, 라이브러리호출 중 데이터 충돌을 방지하기 위해서 이다.
그래서 말한데로 설정해주고 진행했다.
이렇게 main.c에 생성된것을 볼 수 있다.
여기서 osThreadDef함수는 Task 생성 함수이고, myTask02는 Task 함수 Task handle, osPriorityIdle는 우선순위, 256은 스택 사이즈임을 알아두자
밑으로 내려가면 StartTask02함수가 보인다.
그곳을 아래와 같이 추가해주자 (내부 LED를 사용했음)
void StartTask02(void const * argument)
{
/* USER CODE BEGIN StartTask02 */
/* Infinite loop */
for(;;)
{
HAL_GPIO_TogglePin(GPIO_PC13_D2_GPIO_Port, GPIO_PC13_D2_Pin);
osDelay(200);
}
/* USER CODE END StartTask02 */
}
깜빡임은 알아서 확인하도록하고, 다음 실습으로 넘어가자
이번 실습은 위 실습에서 Task2개를 더 추가하여 하나는 버튼을 누르면 켜지고 버튼을 누르지 않으면 꺼지고하는 것과, 하나는 uart로 내 이름을 1초마다 모니터에 출력할 것이다.
UML은 다음과 같다.
내가 사용하는 보드에는 UART를 따로 구비해야한다.
다음은 칩 설정이다.
위처럼 먼저 uart를 인터럽트 방식으로 다룰 예정이므로 다음과 같이 설정해준다.
그리고 개발보드의 버튼을 사용할 건데 회로도를 참고하면
PA0에 연결되어 있음을 알 수 있다.
따라서 PA0을 Input으로 설정하고, LED Red (PB3)는 하나 달아주자. (저항은 330사용예정)
코드는 다음과 같다
/* USER CODE BEGIN Header_StartDefaultTask */
/**
* @brief Function implementing the defaultTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void const * argument)
{
/* USER CODE BEGIN 5 */
/* Infinite loop */
for(;;)
{
HAL_GPIO_TogglePin(GPIO_PC13_D2_GPIO_Port, GPIO_PC13_D2_Pin);
osDelay(200);
}
/* USER CODE END 5 */
}
/* USER CODE BEGIN Header_StartTask02 */
/**
* @brief Function implementing the myTask02 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask02 */
void StartTask02(void const * argument)
{
/* USER CODE BEGIN StartTask02 */
/* Infinite loop */
for(;;)
{
printf("park\r\n");
osDelay(1000);
}
/* USER CODE END StartTask02 */
}
/* USER CODE BEGIN Header_StartTask03 */
/**
* @brief Function implementing the myTask03 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask03 */
void StartTask03(void const * argument)
{
/* USER CODE BEGIN StartTask03 */
/* Infinite loop */
for(;;)
{
if(HAL_GPIO_ReadPin(Button_S2_GPIO_Port, Button_S2_Pin)){
HAL_GPIO_WritePin(LED_R_GPIO_Port, LED_R_Pin, GPIO_PIN_SET);
}else{
HAL_GPIO_WritePin(LED_R_GPIO_Port, LED_R_Pin, GPIO_PIN_RESET);
}
osDelay(10);
}
/* USER CODE END StartTask03 */
}
https://youtube.com/shorts/xyvs-JgDLxE?feature=share
여기서 메인에 있는 while은 그럼 뭘하나요? 라는 궁금증이 발생할 수 있다.
FreeRTOS가 실행되면, 제어권은 커널에 넘어가고, 커널은 스케줄링된 태스크들만 실행하기 때문에
FreeRTOS의 osKernelStart() 함수가 호출된 이후에는 main의 while 루프는 더 이상 실행되지 않는다.
만약 main의 while 루프를 사용하려면 FreeRTOS를 사용하지 않거나, FreeRTOS와 별도로 super loop 방식으로 구현해야한다.
이렇게 간단한 실습을 마쳤다.
다음 포스팅도 RTOS에 대한 실습을 하나 더 진행 할 예정이다.
'STM32' 카테고리의 다른 글
STM32로 진동 감지 센서 + 7세그먼트 제어 - 1 (1) | 2024.12.23 |
---|---|
STM32로 DFR0027를 다루어 보기 (0) | 2024.12.22 |
STM32 익히기 1) (1) | 2024.12.02 |
RTC사용해보기 (0) | 2024.11.26 |
I2C로 LCD 제어해보기 (0) | 2024.11.25 |