FreeRTOS Lab 1: Task 與 Queue

Posted by blueskyson on April 17, 2022

環境: wnidows 10, STM32CubeIDE 1.8.0

開發板: stm32f407g

環境設定

首先編輯 .ioc 檔案

  • PA0 設為 GPIO_Input,並且將 PA0 的 Label 設為 btn_blue
  • PD12PD15 設為 GPIO_Output,Label 設為 led_greenled_orangeled_redled_blue

接下來設置好 FreeRTOS 的執行環境,因為網路很多教學,例如這篇,所以就不贅述。

Lab 目標

  • LED_Task: state 0: First, only Green LED lights up for 2 seconds, and then only Red LED lights up for 2 seconds, and then switches back to the Green LED, then Red, and so on.
  • LED_Task: state 1: Only ORANGE LED is blinking (1 second ON, 1 second OFF, …).
  • Button_Task: If the button is pressed, the LED-task will switch to the other state.

撰寫主程式

編輯 Core/Src/main.c,引入標頭檔:

1
2
3
4
5
/* USER CODE BEGIN Includes */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
/* USER CODE END Includes */

宣告全域變數 xQueue 作為 LED_TaskButton_Task 傳遞訊息的佇列、宣告 struct TaskMessage 作為傳遞訊息的資料結構。

1
2
3
4
5
TaskHandle_t xHandle=NULL;
QueueHandle_t xQueue;
struct TaskMessage {
	int state;
};

撰寫 Button_Task,當按鈕被按下時,將當前的 state 傳遞到 xQueue 中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void Button_Task(void *pvParameters) {
	int pushed = 0;
	static struct TaskMessage mesg = {.state = 0};
	for (;;) {
		if (HAL_GPIO_ReadPin(btn_blue_GPIO_Port, btn_blue_Pin)) {
			if (!pushed) {
				mesg.state ^= 1;
				xQueueSend(xQueue, &mesg, 0);
				pushed = 1;
			}
		} else {
			pushed = 0;
		}
	}
}

撰寫 LED_Task,嘗試從 xQueue 抓取當前的 state,並且執行 LED 閃爍的功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
void LED_Task(void *pvParameters) {
	int msec = 0;
	int state = 0;
	struct TaskMessage mesg;

	for (;;) {
		if (xQueueReceive(xQueue, &mesg, 0) == pdPASS) {
			if (mesg.state == 0) {
				HAL_GPIO_WritePin(led_orange_GPIO_Port, led_orange_Pin, GPIO_PIN_RESET);
				msec = 0;
			} else {
				HAL_GPIO_WritePin(led_red_GPIO_Port, led_red_Pin, GPIO_PIN_RESET);
				HAL_GPIO_WritePin(led_green_GPIO_Port, led_green_Pin, GPIO_PIN_RESET);
			}
			state = mesg.state;
		}

		if (state == 0) {	// state 0
			if (msec < 2000) {
				HAL_GPIO_WritePin(led_green_GPIO_Port, led_green_Pin, GPIO_PIN_SET);
				HAL_GPIO_WritePin(led_red_GPIO_Port, led_red_Pin, GPIO_PIN_RESET);
			} else if (msec < 4000) {
				HAL_GPIO_WritePin(led_green_GPIO_Port, led_green_Pin, GPIO_PIN_RESET);
				HAL_GPIO_WritePin(led_red_GPIO_Port, led_red_Pin, GPIO_PIN_SET);
			} else {
				msec = 0;
				HAL_GPIO_WritePin(led_green_GPIO_Port, led_green_Pin, GPIO_PIN_SET);
				HAL_GPIO_WritePin(led_red_GPIO_Port, led_red_Pin, GPIO_PIN_RESET);
			}
		} else {			// state 1
			if (msec < 1000) {
				HAL_GPIO_WritePin(led_orange_GPIO_Port, led_orange_Pin, GPIO_PIN_SET);
			} else if (msec < 2000) {
				HAL_GPIO_WritePin(led_orange_GPIO_Port, led_orange_Pin, GPIO_PIN_RESET);
			} else {
				msec = 0;
				HAL_GPIO_WritePin(led_orange_GPIO_Port, led_orange_Pin, GPIO_PIN_SET);
			}
		}

		vTaskDelay(1);
		msec++;
	}
}

最後在 main() 函式創建 LED_TaskButton_Task 讓 FreeRTOS 排程:

1
2
3
4
5
6
7
/* USER CODE BEGIN 2 */
xQueue = xQueueCreate(3, sizeof(struct TaskMessage));
xTaskCreate(LED_Task, "LED_Task", 128, NULL, 1, &xHandle);
xTaskCreate(Button_Task, "Button_Task", 128, NULL, 1, &xHandle);

vTaskStartScheduler();
/* USER CODE END 2 */

Demo