반응형

https://youtube.com/live/vSkSt9_30jQ

[STM32#21] freeRTOS를 적용하는 방법과 메시지큐(osMessageQueueId_t)를 이용해서 데이터를 주고받는 방법 간단하게 알아보기!(녹칸다 내맘대로 STM32)

심심한녹칸다의 내맘대로 STM32시리즈이다!

STM32시리즈의 모든 자료는 구글 슬라이드에 작성하고 모두에게 공유되어있음!
https://docs.google.com/presentation/d/1myA5iYbjuKsLWLqtRLKAiRfwUwvqB1d1RGjiMIIgp3I/edit?slide=id.g3b24791482c_1_0#slide=id.g3b24791482c_1_0

STM32에서 freeRTOS를 사용하는 방법을 아주 간단히만 알아보겠습니다!

1.main 루프에서 HAL_getTick을 이용해서 2개의 task를 구현하는 방법에 대해서 보이시오!
-task1 : PB3을 1000밀리초 간격으로 깜빡인다!
-task2 : PB13을 1500밀리초 간격으로 깜빡인다!

/* USER CODE BEGIN 2 */
 uint32_t t1 = 0;
 uint32_t t2 = 0;
 /* USER CODE END 2 */
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
	  //-task1 : PB3을 1000밀리초 간격으로 깜빡인다!
	  if(HAL_GetTick() - t1 >= 1000){
		  t1 = HAL_GetTick();
		  HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_3);
	  }
	  //-task2 : PB13을 1500밀리초 간격으로 깜빡인다!
	  if(HAL_GetTick() - t2 >= 1500){
		  t2 = HAL_GetTick();
		  HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_13);
	  }
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }


2.task1을 TIM1에 task2를 TIM2에 적용해서 LED를 깜빡이시오!

/* USER CODE BEGIN 0 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
   //TIM2일수도있고 TIM3일수도있고~
	if (htim->Instance == TIM2)
	{
		// TASK1
		HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_3);
	}
	else if (htim->Instance == TIM3)
	{
		// TASK2
		HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_13);
	}
}
/* USER CODE END 0 */

/* USER CODE BEGIN 2 */
 HAL_TIM_Base_Start_IT(&htim2);
 HAL_TIM_Base_Start_IT(&htim3);
 /* USER CODE END 2 */
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
	  //메인루트에서는 할일 없음!
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }


3.cubeide에서 tim1을 클락소스로 지정하고 rtos로 task2개를 생성해서 작동시키는 예시를 보이시오!

void StartDefaultTask(void *argument)
{
 /* USER CODE BEGIN 5 */
 /* Infinite loop */
 for(;;)
 {
	  //task1
	  HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_3);
	  osDelay(1000);
 }
 /* USER CODE END 5 */
}

void StartTask02(void *argument)
{
 /* USER CODE BEGIN StartTask02 */
 /* Infinite loop */
 for(;;)
 {
	  //task2
	  HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_13);
	  osDelay(1500);
 }
 /* USER CODE END StartTask02 */
}


4.아래와 같이 task를 구성해서 예제를 구현하시오!
-task1 : 1000밀리초 간격으로 task1의 내부변수값을 usart2에 출력한다!
-task2 : 1000밀리초 간격으로 task2의 내부변수값을 usart2에 출력한다!

void StartDefaultTask(void *argument)
{
 /* USER CODE BEGIN 5 */
 /* Infinite loop */
 int num = 1234;
 char buff[20];
 for(;;)
 {
	  //task1
	  sprintf(buff,"TASK1=%d\n",num);
	  HAL_UART_Transmit(&huart2,buff,strlen(buff),100);
	  osDelay(1000);
 }
 /* USER CODE END 5 */
}
void StartTask02(void *argument)
{
 /* USER CODE BEGIN StartTask02 */
 /* Infinite loop */
 int num = 5678;
 char buff[20];
 for(;;)
 {
	  //task2
	  sprintf(buff,"TASK2=%d\n",num);
	  HAL_UART_Transmit(&huart2,buff,strlen(buff),100);
	  osDelay(1000);
 }
 /* USER CODE END StartTask02 */
}


5.예제 4에서 아래와 같이 task를 구성하고 메시지큐를 활용해서 충돌이 나는것을 방지하시오!
-task1 : 1000밀리초 간격으로 내부에 있는 변수값을 메시지큐에 넣는다!(생산자)
-task2 : 1000밀리초 간격으로 내부에 있는 변수값을 메시지큐에 넣는다!(생산자)
-task3 : 메시지큐에 있는 내용을 usart2에 출력한다!(소비자)

/* USER CODE BEGIN 0 */
//주고받는 데이터 (사용자 정의)
typedef struct {
   uint16_t id;
   int value;
} Msg_t;
//메시지 큐(전역)
osMessageQueueId_t dataQueue;
/* USER CODE END 0 */
/* USER CODE BEGIN 2 */
 //메시지큐(메인)
 dataQueue = osMessageQueueNew(
                   8,              // queue length
                   sizeof(Msg_t),  // item size
                   NULL);
 /* USER CODE END 2 */

void StartDefaultTask(void *argument)
{
 /* USER CODE BEGIN 5 */
 /* Infinite loop */
 int num = 1234;
 Msg_t msg;
 msg.id  = 1;
 for(;;)
 {
	  //task1(공급자)
	  msg.value = num;
	  osMessageQueuePut(dataQueue, &msg, 0, 0); //non-blocking
	  osDelay(1000);
 }

void StartTask02(void *argument)
{
 /* USER CODE BEGIN StartTask02 */
 /* Infinite loop */
 int num = 5678;
 Msg_t msg;
 msg.id  = 2;
 for(;;)
 {
	  //task2(공급자)
	  msg.value = num;
	  osMessageQueuePut(dataQueue, &msg, 0, 0); //non-blocking
	  osDelay(1000);
 }
void StartTask03(void *argument)
{
 /* USER CODE BEGIN StartTask03 */
 /* Infinite loop */
 Msg_t msg;
 char buff[30];
 for(;;)
 {
	  //소비자
	  //dataQueue에 공급자가 넣은 데이터가 없으면 무한대기
	  osMessageQueueGet(dataQueue, &msg, NULL, osWaitForever); //blocking
	  sprintf(buff,"id=%d, value=%d\n",msg.id,msg.value);
	  HAL_UART_Transmit(&huart2,buff,strlen(buff),100);
 }
 /* USER CODE END StartTask03 */
}


6.예제5에서 공급자가 소비자보다 큐에 데이터를 넣는 속도가 더 빠르면 큐가 용량초과가 발생할 수 있다! 간단하게 예외처리하는 기법에 대해서 예제로 만드시오!

/* USER CODE BEGIN 0 */
//주고받는 데이터 (사용자 정의)
typedef struct {
   uint16_t id;
   int value;
} Msg_t;
//메시지 큐(전역)
osMessageQueueId_t dataQueue;
/* USER CODE END 0 */
/* USER CODE BEGIN 2 */
 //메시지큐(메인)
 dataQueue = osMessageQueueNew(
                   8,              // queue length
                   sizeof(Msg_t),  // item size
                   NULL);
 /* USER CODE END 2 */

void StartDefaultTask(void *argument)
{
 /* USER CODE BEGIN 5 */
 /* Infinite loop */
 int num = 1234;
 Msg_t msg;
 msg.id  = 1;
 for(;;)
 {
	  //task1(공급자)
	  msg.value = num;
	  if(osMessageQueuePut(dataQueue, &msg, 0, 0) == osOK){
		  //큐에 빈공간이 있어서 성공적으로 넣었다!
	  }else{
		  //큐에 빈공간이 없어서 실패했다!
	  }

	  osDelay(1000);
 }

void StartTask02(void *argument)
{
 /* USER CODE BEGIN StartTask02 */
 /* Infinite loop */
 int num = 5678;
 Msg_t msg;
 msg.id  = 2;
 for(;;)
 {
	  //task2(공급자)
	  msg.value = num;
	  if(osMessageQueuePut(dataQueue, &msg, 0, 0) == osOK){
		  //큐에 빈공간이 있어서 성공적으로 넣었다!
	  }else{
		  //큐에 빈공간이 없어서 실패했다!
	  }

	  osDelay(1000);
 }
void StartTask03(void *argument)
{
 /* USER CODE BEGIN StartTask03 */
 /* Infinite loop */
 Msg_t msg;
 char buff[30];
 for(;;)
 {
	  //소비자
	  //dataQueue에 공급자가 넣은 데이터가 없으면 무한대기
	  osMessageQueueGet(dataQueue, &msg, NULL, osWaitForever); //blocking
	  sprintf(buff,"id=%d, value=%d\n",msg.id,msg.value);
	  HAL_UART_Transmit(&huart2,buff,strlen(buff),100);
 }
 /* USER CODE END StartTask03 */
}


7.아래와 같이 task를 구현해서 usart2로 출력하시오!
-task1 : 1000밀리초 간격으로 num1의 값은 1씩 증가하고 num2의 값은 1씩 감소시켜서 큐에 넣는다!
-task2 : 1000밀리초 간격으로 num1의 값은 1씩 증가하고 num2의 값은 1씩 감소시켜서 큐에 넣는다!
-task3 : 메시지큐에 있는 내용을 usart2에 출력한다!(소비자)

/* USER CODE BEGIN 0 */
//주고받는 데이터 (사용자 정의)
typedef struct {
   uint16_t id;
   int value1;
   int value2;
} Msg_t;
//메시지 큐(전역)
osMessageQueueId_t dataQueue;
/* USER CODE END 0 */
/* USER CODE BEGIN 2 */
 //메시지큐(메인)
 dataQueue = osMessageQueueNew(
                   8,              // queue length
                   sizeof(Msg_t),  // item size
                   NULL);
 /* USER CODE END 2 */

void StartDefaultTask(void *argument)
{
 /* USER CODE BEGIN 5 */
 /* Infinite loop */
 Msg_t msg = {1,0,0};
 for(;;)
 {
	  //task1(공급자)
	  msg.value1++;
	  msg.value2--;
	  if(osMessageQueuePut(dataQueue, &msg, 0, 0) == osOK){
		  //큐에 빈공간이 있어서 성공적으로 넣었다!
	  }else{
		  //큐에 빈공간이 없어서 실패했다!
	  }
	  osDelay(1000);
 }
 /* USER CODE END 5 */
}
void StartTask02(void *argument)
{
 /* USER CODE BEGIN StartTask02 */
 /* Infinite loop */
 Msg_t msg = {2,0,0};
 for(;;)
 {
	  //task2(공급자)
	  msg.value1++;
	  msg.value2--;
	  if(osMessageQueuePut(dataQueue, &msg, 0, 0) == osOK){
		  //큐에 빈공간이 있어서 성공적으로 넣었다!
	  }else{
		  //큐에 빈공간이 없어서 실패했다!
	  }
	  osDelay(1000);
 }
 /* USER CODE END StartTask02 */
}

void StartTask03(void *argument)
{
 /* USER CODE BEGIN StartTask03 */
 /* Infinite loop */
 Msg_t msg;
 char buff[30];
 for(;;)
 {
	  //소비자
	  //dataQueue에 공급자가 넣은 데이터가 없으면 무한대기
	  osMessageQueueGet(dataQueue, &msg, NULL, osWaitForever); //blocking
	  sprintf(buff,"id=%d, value1=%d, value2=%d\n",msg.id,msg.value1,msg.value2);
	  HAL_UART_Transmit(&huart2,buff,strlen(buff),100);
 }
 /* USER CODE END StartTask03 */
}


8.아래와 같이 task를 구현하시오!
-task1 : 100밀리초 간격으로 LED 8개가 링모양으로 순차적으로 켜진다!
-task2 : 1초 간격으로 1씩 증가하는 카운터값을 usart2로 전송하시오!

/* USER CODE BEGIN 0 */
GPIO_TypeDef *mygpio[] = {GPIOB,GPIOB,GPIOB,GPIOB,GPIOB,GPIOB,GPIOC,GPIOB};
uint16_t mypin[] = {GPIO_PIN_3,GPIO_PIN_13,GPIO_PIN_5,GPIO_PIN_14,GPIO_PIN_4,GPIO_PIN_15,GPIO_PIN_4,GPIO_PIN_7};
/* USER CODE END 0 */
void StartDefaultTask(void *argument)
{
 /* USER CODE BEGIN 5 */
 /* Infinite loop */
 int led_num = 0;
 for(;;)
 {
	  //task1
	  //100밀리초 간격으로 LED를 빙글빙글돌린다
	  for(int i = 0;i<8;i++){
		  //led_num와 i가 같은 녀석만 켜고 나머지는 끈다!
		  if(led_num == i){
			  HAL_GPIO_WritePin(mygpio[i], mypin[i], 1);
		  }else{
			  HAL_GPIO_WritePin(mygpio[i], mypin[i], 0);
		  }
	  }
	  led_num++;
	  if(led_num == 8) led_num = 0;
	  osDelay(100);
 }


void StartTask02(void *argument)
{
 /* USER CODE BEGIN StartTask02 */
 /* Infinite loop */
 int num = 0;
 char buff[30];
 for(;;)
 {
	  sprintf(buff,"num = %d\n",num);
	  HAL_UART_Transmit(&huart2,buff,strlen(buff),100);
	  num++;
	  osDelay(1000);
 }
 /* USER CODE END StartTask02 */
}

 

반응형
Posted by 덕력킹
,