FreeRTOS

25k words

1、动态创建任务

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#include "main.h"
#include "driver_led.h"
#include "driver_key.h"
void FreeRTOS_Start(void);
int main(void)
{
// 初始化HAL库函数必须要调用此函数
HAL_Init();
// 系统时钟即AHB/APB时钟配置
SystemClock_Config();

// 初始化LED
LedGpioInit();
KeyInit();
FreeRTOS_Start();
}
TaskHandle_t start_task_handle;
TaskHandle_t task1_handle;
TaskHandle_t task2_handle;
TaskHandle_t task3_handle;

void StartTask(void);
void Task1(void);
void Task2(void);
void Task3(void);
void FreeRTOS_Start(void)
{
xTaskCreate(
(TaskFunction_t) StartTask, //任务函数的地址
(char *) "StartTask", //任务函数的名称
(uint16_t) 128, //任务函数栈空间大小
(void *) NULL, //任务函数的参数
(UBaseType_t) 1, //任务函数的优先级
(TaskHandle_t*) &start_task_handle //任务函数的句柄
);

//启动调度器
vTaskStartScheduler();

}

void StartTask(void)
{
taskENTER_CRITICAL();
xTaskCreate(
(TaskFunction_t) Task1,
(char *) "Task1",
(uint16_t) 128,
(void *) NULL,
(UBaseType_t) 2,
(TaskHandle_t*) &task1_handle
);
xTaskCreate(
(TaskFunction_t) Task2,
(char *) "Task2",
(uint16_t) 128,
(void *) NULL,
(UBaseType_t) 3,
(TaskHandle_t*) &task2_handle
);
xTaskCreate(
(TaskFunction_t) Task3,
(char *) "Task3",
(uint16_t) 128,
(void *) NULL,
(UBaseType_t) 4,
(TaskHandle_t*) &task3_handle
);
vTaskDelete(NULL);
taskEXIT_CRITICAL();
}

void Task1(void)
{
while(1)
{
LED_TOGGLE(LED0_GPIO_PORT,LED0_GPIO_PIN);
vTaskDelay(500);
}
}
void Task2(void)
{
while(1)
{
LED_TOGGLE(LED1_GPIO_PORT,LED1_GPIO_PIN);
vTaskDelay(500);
}
}
void Task3(void)
{
while(1)
{
if(KeyScan() == 0)
{
if(task1_handle != NULL) vTaskDelete(task1_handle);
task1_handle = NULL;
}
vTaskDelay(500);
}
}

2、静态创建任务

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
#include "main.h"
#include "driver_led.h"
#include "driver_key.h"

/* 启动任务的配置 */
#define START_TASK_STACK 128
#define START_TASK_PRIORITY 1
TaskHandle_t start_task_handle;
StackType_t start_task_stack[START_TASK_STACK]; // 静态任务的任务栈,以数组形式存储
StaticTask_t start_task_tcb; // 静态任务的TCB结构体类型
void start_task(void);

/* 任务1的配置 */
#define TASK1_STACK 128
#define TASK1_PRIORITY 2
TaskHandle_t task1_handle;
StackType_t task1_stack[TASK1_STACK]; // 静态任务的任务栈,以数组形式存储
StaticTask_t task1_tcb; // 静态任务的TCB结构体类型
void task1(void);

/* 任务2的配置 */
#define TASK2_STACK 128
#define TASK2_PRIORITY 3
TaskHandle_t task2_handle;
StackType_t task2_stack[TASK2_STACK]; // 静态任务的任务栈,以数组形式存储
StaticTask_t task2_tcb; // 静态任务的TCB结构体类型
void task2(void);

/* 任务3的配置 */
#define TASK3_STACK 128
#define TASK3_PRIORITY 4
TaskHandle_t task3_handle;
StackType_t task3_stack[TASK3_STACK]; // 静态任务的任务栈,以数组形式存储
StaticTask_t task3_tcb; // 静态任务的TCB结构体类型
void task3(void);

/* ======================= 静态创建方式,需要手动指定2个特殊任务的资源=============================== */
/* 空闲任务的配置 */
StackType_t idle_task_stack[configMINIMAL_STACK_SIZE]; // 静态任务的任务栈,以数组形式存储
StaticTask_t idle_task_tcb; // 静态任务的TCB结构体类型

/* 软件定时器任务的配置 */
StackType_t timer_task_stack[configTIMER_TASK_STACK_DEPTH]; // 静态任务的任务栈,以数组形式存储
StaticTask_t timer_task_tcb; // 静态任务的TCB结构体类型

/* 分配空闲任务的资源 */
void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer,
StackType_t **ppxIdleTaskStackBuffer,
uint32_t *pulIdleTaskStackSize)
{
*ppxIdleTaskTCBBuffer = &idle_task_tcb;
*ppxIdleTaskStackBuffer = idle_task_stack;
*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
}

/* 分配软件定时器任务的资源 */
void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer,
StackType_t **ppxTimerTaskStackBuffer,
uint32_t *pulTimerTaskStackSize)
{
*ppxTimerTaskTCBBuffer = &timer_task_tcb;
*ppxTimerTaskStackBuffer = timer_task_stack;
*pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
}

/**
* @description: 启动FreeRTOS
* @return {*}
*/
void FreeRTOS_Start(void)
{
/* 1.创建一个启动任务 */
start_task_handle = xTaskCreateStatic(
(TaskFunction_t)start_task, // 任务函数的地址
(char *)"start_task", // 任务名字符串
(uint32_t)START_TASK_STACK, // 任务栈大小,默认最小128,单位4字节
(void *)NULL, // 传递给任务的参数
(UBaseType_t)START_TASK_PRIORITY, // 任务的优先级
(StackType_t *)start_task_stack, // 我们创建的任务栈(数组存储)的地址
(StaticTask_t *)&start_task_tcb // 我们创建的tcb的地址
);

/* 2.启动调度器:会自动创建空闲任务和软件定时器(如果开启),
静态创建的方式需要去实现2个分配资源的接口函数 */
vTaskStartScheduler();
}

int main(void)
{
// 初始化HAL库函数必须要调用此函数
HAL_Init();
// 系统时钟即AHB/APB时钟配置
SystemClock_Config();

// 初始化LED
LedGpioInit();
KeyInit();
FreeRTOS_Start();
}

/**
* @description: 启动任务:用来创建其他Task
* @param {void} *pvParameters
* @return {*}
*/
void start_task(void)
{
/* 进入临界区:保护临界区里的代码不会被打断 */
taskENTER_CRITICAL();

/* 使用静态创建3个任务 */
task1_handle = xTaskCreateStatic(
(TaskFunction_t)task1,
(char *)"task1",
(configSTACK_DEPTH_TYPE)TASK1_STACK,
(void *)NULL,
(UBaseType_t)TASK1_PRIORITY,
(StackType_t *)task1_stack, // 我们创建的任务栈(数组存储)的地址
(StaticTask_t *)&task1_tcb // 我们创建的tcb的地址
);

task2_handle = xTaskCreateStatic(
(TaskFunction_t)task2,
(char *)"task2",
(configSTACK_DEPTH_TYPE)TASK2_STACK,
(void *)NULL,
(UBaseType_t)TASK2_PRIORITY,
(StackType_t *)task2_stack, // 我们创建的任务栈(数组存储)的地址
(StaticTask_t *)&task2_tcb // 我们创建的tcb的地址
);

task3_handle = xTaskCreateStatic(
(TaskFunction_t)task3,
(char *)"task3",
(configSTACK_DEPTH_TYPE)TASK3_STACK,
(void *)NULL,
(UBaseType_t)TASK3_PRIORITY,
(StackType_t *)task3_stack, // 我们创建的任务栈(数组存储)的地址
(StaticTask_t *)&task3_tcb // 我们创建的tcb的地址
);

/* 启动任务只需要执行一次即可,用完就删除自己 */
vTaskDelete(NULL);

/* 退出临界区 */
taskEXIT_CRITICAL();
}

void task1(void)
{
while(1)
{
LED_TOGGLE(LED0_GPIO_PORT,LED0_GPIO_PIN);
vTaskDelay(500);
}
}
void task2(void)
{
while(1)
{
LED_TOGGLE(LED1_GPIO_PORT,LED1_GPIO_PIN);
vTaskDelay(500);
}
}
void task3(void)
{
while(1)
{
if(KeyScan() == 0)
{
if(task1_handle != NULL) vTaskDelete(task1_handle);
task1_handle = NULL;
}
vTaskDelay(500);
}
}

3、任务挂起与回复

3.1、任务挂起

1
2
/*传入参数为任务句柄,若传入NULL,则代表挂起当前任务*/
vTaskSuspend(task1_handle);

3.2 任务恢复

1
2
/* 任务恢复,传入参数为任务句柄*/
vTaskResume(task1_handle);

3.3 挂起任务调度器

仅执行当前任务

1
vTaskSuspendAll();

3.4 恢复任务调度器

1
xTaskResumeAll();

3.5 打印任务状态

1
2
/* 传入参数为字符串 */
vTaskList(str);

3.6 中断管理

1
2
3
4
5
/*执行此函数后,在中断优先级阈值以下的中断将被屏蔽*/
portDISABLE_INTERRUPTS();

/* 使能中断 */
portENABLE_INTERRUPTS();

5、时间函数

1
2
3
4
/* 相对延时,每隔n个时间片执行一次代码,不能保证代码执行时间相同 */
vtaskDelay(n);
/* 绝对延时,代码整体执行时间为n个时间片,保证代码执行周期*/
xTaskDelayUntil();

6、任务之间通过队列传输数据

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include "main.h"
#include "driver_led.h"
#include "driver_key.h"
#include "driver_uart.h"

void StartTask(void);
void Task1(void);
void Task2(void);
void FreeRTOS_Start(void);


int main(void)
{
// 初始化HAL库函数必须要调用此函数
HAL_Init();
// 系统时钟即AHB/APB时钟配置
SystemClock_Config();

// 初始化LED
LedInit();
KeyInit();
UartInit(115200);
FreeRTOS_Start();

while(1)
{
HAL_Delay(1000);
UartSendData("hello\r\n");
LED_TOGGLE(LED0_GPIO_PORT,LED0_GPIO_PIN);
}
}
/* 任务句柄,用以保存不同任务的配置 */
TaskHandle_t start_task_handle;
TaskHandle_t task1_handle;
TaskHandle_t task2_handle;

/*
* 函数作用:常规写法,起始任务,用以创建其他任务
* 输入参数:无
* 返回值:无
* 作者:LSK
*/
void FreeRTOS_Start(void)
{
xTaskCreate(
(TaskFunction_t) StartTask, //任务函数的地址
(char *) "StartTask", //任务函数的名称
(uint16_t) 128, //任务函数栈空间大小
(void *) NULL, //任务函数的参数
(UBaseType_t) 1, //任务函数的优先级
(TaskHandle_t*) &start_task_handle //任务函数的句柄
);

/* 启用调度器,负责任务切换*/
vTaskStartScheduler();

}

/* 队列句柄*/
QueueHandle_t handle1;

void StartTask(void)
{
/* 创建一个队列 */
handle1 = xQueueCreate(1,sizeof(char *));
if(handle1 == NULL) UartSendData("task err");

/* 进入临界保护区,保证在临界区的代码不会被打断*/
taskENTER_CRITICAL();
xTaskCreate(
(TaskFunction_t) Task1,
(char *) "Task1",
(uint16_t) 128,
(void *) NULL,
(UBaseType_t) 2,
(TaskHandle_t*) &task1_handle
);
xTaskCreate(
(TaskFunction_t) Task2,
(char *) "Task2",
(uint16_t) 128,
(void *) NULL,
(UBaseType_t) 4,
(TaskHandle_t*) &task2_handle
);
vTaskDelete(NULL); //删除任务本身
/* 退出临界保护区*/
taskEXIT_CRITICAL();
}
/*
* 函数作用:负责创建一个字符串,通过队列发送出去
* 输入参数:无
* 返回值:无
* 作者:LSK
*/
void Task1(void)
{
char* str = "tehsjncncncncc";
while(1)
{
if(KeyScan() == KEY0)
{
/* 往队列插入一个值,并设置阻塞等待*/
xQueueSend(handle1,&str,portMAX_DELAY);
UartSendData("Send Pass\r\n");
}
vTaskDelay(20);
}
}

/*
* 函数作用:接收数据任务
* 输入参数:无
* 返回值:无
* 作者:LSK
*/
void Task2(void)
{
char *buffer;
BaseType_t res;
while(1)
{
/* 接收队列的任务,并进入阻塞等待*/
res = xQueueReceive(handle1,&buffer,portMAX_DELAY);
if(res == pdPASS)
{
UartSendData("buffer:\r\n");
UartSendData(buffer);
UartSendData("\r\n");
}
vTaskDelay(500);
}
}

7、二进制信号量释放与接收

7.1 二进制信号量

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include "main.h"

void StartTask(void);
void Task1(void);
void Task2(void);
void FreeRTOS_Start(void);

int main(void)
{
// 初始化HAL库函数必须要调用此函数
HAL_Init();
// 系统时钟即AHB/APB时钟配置
SystemClock_Config();

// 初始化LED
LedInit();
KeyInit();
UartInit(115200);
FreeRTOS_Start();

while(1)
{
HAL_Delay(1000);
UartSendData("hello\r\n");
LED_TOGGLE(LED0_GPIO_PORT,LED0_GPIO_PIN);
}
}
/* 任务句柄,用以保存不同任务的配置 */
TaskHandle_t start_task_handle;
TaskHandle_t task1_handle;
TaskHandle_t task2_handle;

/*
* 函数作用:常规写法,起始任务,用以创建其他任务
* 输入参数:无
* 返回值:无
* 作者:LSK
*/
void FreeRTOS_Start(void)
{
xTaskCreate(
(TaskFunction_t) StartTask, //任务函数的地址
(char *) "StartTask", //任务函数的名称
(uint16_t) 128, //任务函数栈空间大小
(void *) NULL, //任务函数的参数
(UBaseType_t) 1, //任务函数的优先级
(TaskHandle_t*) &start_task_handle //任务函数的句柄
);

/* 启用调度器,负责任务切换*/
vTaskStartScheduler();

}

/* 队列句柄*/
QueueHandle_t handle1;
SemaphoreHandle_t semaphore_handle;

void StartTask(void)
{
/* 创建一个信号量 */
vSemaphoreCreateBinary(semaphore_handle);
if(semaphore_handle != NULL) UartSendData("Create success!\r\n");

/* 创建一个队列 */
handle1 = xQueueCreate(1,sizeof(char *));
if(handle1 == NULL) UartSendData("task err");

/* 进入临界保护区,保证在临界区的代码不会被打断*/
taskENTER_CRITICAL();
xTaskCreate(
(TaskFunction_t) Task1,
(char *) "Task1",
(uint16_t) 128,
(void *) NULL,
(UBaseType_t) 2,
(TaskHandle_t*) &task1_handle
);
xTaskCreate(
(TaskFunction_t) Task2,
(char *) "Task2",
(uint16_t) 128,
(void *) NULL,
(UBaseType_t) 4,
(TaskHandle_t*) &task2_handle
);
vTaskDelete(NULL); //删除任务本身
/* 退出临界保护区*/
taskEXIT_CRITICAL();
}
/*
* 函数作用:释放信号量
* 输入参数:无
* 返回值:无
* 作者:LSK
*/
void Task1(void)
{
BaseType_t res;
while(1)
{
if(KeyScan() == KEY0)
{
/* 释放信号量 */
res = xSemaphoreGive(semaphore_handle);
if (res == pdPASS) UartSendData("Send Pass\r\n");
}
vTaskDelay(20);
}
}

/*
* 函数作用:接收信号量
* 输入参数:无
* 返回值:无
* 作者:LSK
*/
void Task2(void)
{
BaseType_t res;
while(1)
{
/* 接收信号量是否释放 */
res = xSemaphoreTake(semaphore_handle, portMAX_DELAY);
if(res == pdPASS)
{
UartSendData("Take success!\r\n");
UartSendData("\r\n");
}
vTaskDelay(500);
}
}

7.2 互斥二进制信号量

它会将阻塞高优先级的低优先级提升,从而保证高优先级不会被低优先级阻塞。

8、计数信号量释放与接收

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#include "main.h"

void StartTask(void);
void Task1(void);
void Task2(void);
void FreeRTOS_Start(void);

int main(void)
{
// 初始化HAL库函数必须要调用此函数
HAL_Init();
// 系统时钟即AHB/APB时钟配置
SystemClock_Config();

// 初始化LED
LedInit();
KeyInit();
UartInit(115200);
FreeRTOS_Start();

while(1)
{
HAL_Delay(1000);
UartSendData("hello\r\n");
LED_TOGGLE(LED0_GPIO_PORT,LED0_GPIO_PIN);
}
}
/* 任务句柄,用以保存不同任务的配置 */
TaskHandle_t start_task_handle;
TaskHandle_t task1_handle;
TaskHandle_t task2_handle;

/*
* 函数作用:常规写法,起始任务,用以创建其他任务
* 输入参数:无
* 返回值:无
* 作者:LSK
*/
void FreeRTOS_Start(void)
{
xTaskCreate(
(TaskFunction_t) StartTask, //任务函数的地址
(char *) "StartTask", //任务函数的名称
(uint16_t) 128, //任务函数栈空间大小
(void *) NULL, //任务函数的参数
(UBaseType_t) 1, //任务函数的优先级
(TaskHandle_t*) &start_task_handle //任务函数的句柄
);

/* 启用调度器,负责任务切换*/
vTaskStartScheduler();

}

char str[100];
/* 队列句柄*/
QueueHandle_t handle1;

void StartTask(void)
{
UBaseType_t Count = 0;
/* 创建一个信号量 */
handle1 = xSemaphoreCreateCounting(100, 0);
if(!(handle1 == NULL))
{
UartSendData("Create success!\r\n");
Count = uxSemaphoreGetCount(handle1);
sprintf(str, "the init count: %d", Count);
UartSendData(str);
}

/* 进入临界保护区,保证在临界区的代码不会被打断*/
taskENTER_CRITICAL();
xTaskCreate(
(TaskFunction_t) Task1,
(char *) "Task1",
(uint16_t) 128,
(void *) NULL,
(UBaseType_t) 3,
(TaskHandle_t*) &task1_handle
);
xTaskCreate(
(TaskFunction_t) Task2,
(char *) "Task2",
(uint16_t) 128,
(void *) NULL,
(UBaseType_t) 4,
(TaskHandle_t*) &task2_handle
);
vTaskDelete(NULL); //删除任务本身
/* 退出临界保护区*/
taskEXIT_CRITICAL();
}

/*
* 函数作用:释放信号量
* 输入参数:无
* 返回值:无
* 作者:LSK
*/
void Task1(void)
{
BaseType_t res;
while(1)
{
if(KeyScan() == KEY0)
{
/* 释放信号量 */
res = xSemaphoreGive(handle1);
if (res == pdPASS) UartSendData("Send Pass\r\n");
}
vTaskDelay(20);
}
}

/*
* 函数作用:接收信号量
* 输入参数:无
* 返回值:无
* 作者:LSK
*/
void Task2(void)
{
char str[100];
UBaseType_t Count = 0;
BaseType_t res;
while(1)
{
/* 接收信号量是否释放 */
res = xSemaphoreTake(handle1, portMAX_DELAY);
if(res == pdPASS)
{
UartSendData("Take success!\r\n");
UartSendData("\r\n");
UartSendData(str);
}
Count = uxSemaphoreGetCount(handle1);
sprintf(str, "the init count: %d\r\n", Count);
UartSendData(str);
vTaskDelay(1000);
}
}

9、队列集

10、事件标志组

比信号量更灵活,每一个bit位都代表一个信号量。

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include "main.h"

void StartTask(void);
void Task1(void);
void Task2(void);
void FreeRTOS_Start(void);

int main(void)
{
// 初始化HAL库函数必须要调用此函数
HAL_Init();
// 系统时钟即AHB/APB时钟配置
SystemClock_Config();

// 初始化LED
LedInit();
KeyInit();
UartInit(115200);
FreeRTOS_Start();

while(1)
{
HAL_Delay(1000);
UartSendData("hello\r\n");
LED_TOGGLE(LED0_GPIO_PORT,LED0_GPIO_PIN);
}
}

/* 任务句柄,用以保存不同任务的配置 */
TaskHandle_t start_task_handle;
TaskHandle_t task1_handle;
TaskHandle_t task2_handle;

/*
* 函数作用:常规写法,起始任务,用以创建其他任务
* 输入参数:无
* 返回值:无
* 作者:LSK
*/
void FreeRTOS_Start(void)
{
xTaskCreate(
(TaskFunction_t) StartTask, //任务函数的地址
(char *) "StartTask", //任务函数的名称
(uint16_t) 128, //任务函数栈空间大小
(void *) NULL, //任务函数的参数
(UBaseType_t) 1, //任务函数的优先级
(TaskHandle_t*) &start_task_handle //任务函数的句柄
);

/* 启用调度器,负责任务切换*/
vTaskStartScheduler();

}

char str[100];
EventGroupHandle_t event_handle;

void StartTask(void)
{
UBaseType_t Count = 0;
/* 创建一个信号量 */
event_handle = xEventGroupCreate();
if(!(event_handle == NULL))
{
UartSendData("Create success!\r\n");
}
/* 进入临界保护区,保证在临界区的代码不会被打断*/
taskENTER_CRITICAL();
xTaskCreate(
(TaskFunction_t) Task1,
(char *) "Task1",
(uint16_t) 128,
(void *) NULL,
(UBaseType_t) 3,
(TaskHandle_t*) &task1_handle
);
xTaskCreate(
(TaskFunction_t) Task2,
(char *) "Task2",
(uint16_t) 128,
(void *) NULL,
(UBaseType_t) 4,
(TaskHandle_t*) &task2_handle
);
vTaskDelete(NULL); //删除任务本身
/* 退出临界保护区*/
taskEXIT_CRITICAL();
}

/*
* 函数作用:发送事件
* 输入参数:无
* 返回值:无
* 作者:LSK
*/
#define EVENTBIT_0 (1 << 0)
#define EVENTBIT_1 (1 << 1)

void Task1(void)
{
EventBits_t res;
while(1)
{

xEventGroupSetBits(event_handle, 1<<3);
if(KeyScan() == KEY0)
{
/* 设置标志位*/
res = xEventGroupSetBits(event_handle, EVENTBIT_0);
sprintf(str,"event flag: %#x\r\n", res);
UartSendData(str);
res = xEventGroupSetBits(event_handle, EVENTBIT_1);
sprintf(str,"event flag: %#x\r\n", res);
UartSendData(str);

UartSendData("KEY0 PRESS!\r\n");
}
vTaskDelay(20);
}
}

/*
* 函数作用:接收事件
* 输入参数:无
* 返回值:无
* 作者:LSK
*/
void Task2(void)
{
EventBits_t res;
while(1)
{
/* 接收信号量是否释放 */
res = xEventGroupWaitBits(
event_handle, // 事件句柄
((EVENTBIT_0 | EVENTBIT_1)), // 等待的标志位
pdTRUE, // 是否清楚标志位
pdTRUE, // 是否等待标志位
portMAX_DELAY // 等待事件
);
sprintf(str, "task2: %x\r\n", res);
UartSendData(str);
}
}

11 任务通知

11.1 任务通知模拟信号量

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include "main.h"
#include "portmacro.h"
#include "projdefs.h"
#include <stdint.h>


void StartTask(void);
void Task1(void);
void Task2(void);
void FreeRTOS_Start(void);

int main(void)
{
// 初始化HAL库函数必须要调用此函数
HAL_Init();
// 系统时钟即AHB/APB时钟配置
SystemClock_Config();
// 初始化LED
LedInit();
KeyInit();
UartInit(115200);
FreeRTOS_Start();

while(1)
{
HAL_Delay(1000);
UartSendData("hello\r\n");
LED_TOGGLE(LED0_GPIO_PORT,LED0_GPIO_PIN);
}
}

/* 任务句柄,用以保存不同任务的配置 */
TaskHandle_t start_task_handle;
TaskHandle_t task1_handle;
TaskHandle_t task2_handle;

/*
* 函数作用:常规写法,起始任务,用以创建其他任务
* 输入参数:无
* 返回值:无
* 作者:LSK
*/
void FreeRTOS_Start(void)
{
xTaskCreate(
(TaskFunction_t) StartTask, //任务函数的地址
(char *) "StartTask", //任务函数的名称
(uint16_t) 128, //任务函数栈空间大小
(void *) NULL, //任务函数的参数
(UBaseType_t) 1, //任务函数的优先级
(TaskHandle_t*) &start_task_handle //任务函数的句柄
);

/* 启用调度器,负责任务切换*/
vTaskStartScheduler();

}
char str[100];

void StartTask(void)
{
/* 进入临界保护区,保证在临界区的代码不会被打断*/
taskENTER_CRITICAL();
xTaskCreate(
(TaskFunction_t) Task1,
(char *) "Task1",
(uint16_t) 128,
(void *) NULL,
(UBaseType_t) 3,
(TaskHandle_t*) &task1_handle
);
xTaskCreate(
(TaskFunction_t) Task2,
(char *) "Task2",
(uint16_t) 128,
(void *) NULL,
(UBaseType_t) 4,
(TaskHandle_t*) &task2_handle
);
vTaskDelete(NULL); //删除任务本身
/* 退出临界保护区*/
taskEXIT_CRITICAL();
}

/*
* 函数作用:任务通知发送
* 输入参数:无
* 返回值:无
* 作者:LSK
*/
void Task1(void)
{
EventBits_t res;
while(1)
{
if(KeyScan() == KEY0)
{
/* 实际使取出task2的通知值,然后+1*/
xTaskNotifyGive(task2_handle);
UartSendData("KEY0 PRESS!\r\n");
}
vTaskDelay(200);
}
}

/*
* 函数作用:任务通知接收
* 输入参数:无
* 返回值:无
* 作者:LSK
*/
void Task2(void)
{
uint32_t res_notify;
while(1)
{
res_notify = ulTaskNotifyTake(
pdTRUE, //接收完通知后,是否对通知值处理,pdTRUE:置0;pdFALSE:-1
portMAX_DELAY //设置等待时间
);
sprintf(str, "task2 notify: %d\r\n", res_notify);
UartSendData(str);
}
}

11.2 任务通知模拟消息队列(邮箱)

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include "main.h"
#include "portmacro.h"
#include "projdefs.h"
#include <stdint.h>


void StartTask(void);
void Task1(void);
void Task2(void);
void FreeRTOS_Start(void);

int main(void)
{
// 初始化HAL库函数必须要调用此函数
HAL_Init();
// 系统时钟即AHB/APB时钟配置
SystemClock_Config();
// 初始化LED
LedInit();
KeyInit();
UartInit(115200);
FreeRTOS_Start();

while(1)
{
HAL_Delay(1000);
UartSendData("hello\r\n");
LED_TOGGLE(LED0_GPIO_PORT,LED0_GPIO_PIN);
}
}

/* 任务句柄,用以保存不同任务的配置 */
TaskHandle_t start_task_handle;
TaskHandle_t task1_handle;
TaskHandle_t task2_handle;

/*
* 函数作用:常规写法,起始任务,用以创建其他任务
* 输入参数:无
* 返回值:无
* 作者:LSK
*/
void FreeRTOS_Start(void)
{
xTaskCreate(
(TaskFunction_t) StartTask, //任务函数的地址
(char *) "StartTask", //任务函数的名称
(uint16_t) 128, //任务函数栈空间大小
(void *) NULL, //任务函数的参数
(UBaseType_t) 1, //任务函数的优先级
(TaskHandle_t*) &start_task_handle //任务函数的句柄
);

/* 启用调度器,负责任务切换*/
vTaskStartScheduler();

}
char str[100];

void StartTask(void)
{
/* 进入临界保护区,保证在临界区的代码不会被打断*/
taskENTER_CRITICAL();
xTaskCreate(
(TaskFunction_t) Task1,
(char *) "Task1",
(uint16_t) 128,
(void *) NULL,
(UBaseType_t) 3,
(TaskHandle_t*) &task1_handle
);
xTaskCreate(
(TaskFunction_t) Task2,
(char *) "Task2",
(uint16_t) 128,
(void *) NULL,
(UBaseType_t) 4,
(TaskHandle_t*) &task2_handle
);
vTaskDelete(NULL); //删除任务本身
/* 退出临界保护区*/
taskEXIT_CRITICAL();
}

/*
* 函数作用:模拟消息队列发送
* 输入参数:无
* 返回值:无
* 作者:LSK
*/
void Task1(void)
{
EventBits_t res;
while(1)
{
if(KeyScan() == KEY0)
{
xTaskNotify(task2_handle, // 要发送的任务句柄
100, // 要发送的数据
eSetValueWithOverwrite // 发送方式
);
UartSendData("KEY0 PRESS!\r\n");
}
vTaskDelay(200);
}
}

/*
* 函数作用:模拟消息队列接收
* 输入参数:无
* 返回值:无
* 作者:LSK
*/
void Task2(void)
{
uint32_t res_notify;
while(1)
{
xTaskNotifyWait(
0x00000000, // 接收通知前是否清楚通知值,按位,全为0表示不不清楚
0xffffffff, // 接收通知后是否要清楚通知值,按位,全为f表示清楚
&res_notify, // 接受值存放地址
portMAX_DELAY // 等待事件
);
sprintf(str, "task2 notify: %d\r\n", res_notify);
UartSendData(str);
}
}

11.3 模拟事件标志组

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include "main.h"
#include "portmacro.h"
#include "projdefs.h"
#include <stdint.h>


void StartTask(void);
void Task1(void);
void Task2(void);
void FreeRTOS_Start(void);

int main(void)
{
// 初始化HAL库函数必须要调用此函数
HAL_Init();
// 系统时钟即AHB/APB时钟配置
SystemClock_Config();
// 初始化LED
LedInit();
KeyInit();
UartInit(115200);
FreeRTOS_Start();

while(1)
{
HAL_Delay(1000);
UartSendData("hello\r\n");
LED_TOGGLE(LED0_GPIO_PORT,LED0_GPIO_PIN);
}
}

/* 任务句柄,用以保存不同任务的配置 */
TaskHandle_t start_task_handle;
TaskHandle_t task1_handle;
TaskHandle_t task2_handle;

/*
* 函数作用:常规写法,起始任务,用以创建其他任务
* 输入参数:无
* 返回值:无
* 作者:LSK
*/
void FreeRTOS_Start(void)
{
xTaskCreate(
(TaskFunction_t) StartTask, //任务函数的地址
(char *) "StartTask", //任务函数的名称
(uint16_t) 128, //任务函数栈空间大小
(void *) NULL, //任务函数的参数
(UBaseType_t) 1, //任务函数的优先级
(TaskHandle_t*) &start_task_handle //任务函数的句柄
);

/* 启用调度器,负责任务切换*/
vTaskStartScheduler();

}
char str[100];

void StartTask(void)
{
/* 进入临界保护区,保证在临界区的代码不会被打断*/
taskENTER_CRITICAL();
xTaskCreate(
(TaskFunction_t) Task1,
(char *) "Task1",
(uint16_t) 128,
(void *) NULL,
(UBaseType_t) 3,
(TaskHandle_t*) &task1_handle
);
xTaskCreate(
(TaskFunction_t) Task2,
(char *) "Task2",
(uint16_t) 128,
(void *) NULL,
(UBaseType_t) 4,
(TaskHandle_t*) &task2_handle
);
vTaskDelete(NULL); //删除任务本身
/* 退出临界保护区*/
taskEXIT_CRITICAL();
}

/*
* 函数作用:模拟事件标志组发送
* 输入参数:无
* 返回值:无
* 作者:LSK
*/
void Task1(void)
{
EventBits_t res;
while(1)
{
if (KeyScan() == KEY0) {
xTaskNotify(task2_handle, // 要发送的任务句柄
1 << 8, // 要发送的数据位
eSetBits // 发送方式
);
UartSendData("KEY0 PRESS!\r\n");
}
vTaskDelay(200);
}
}

/*
* 函数作用:模拟事件标志组接收
* 输入参数:无
* 返回值:无
* 作者:LSK
*/
void Task2(void)
{
uint32_t res_notify;
while (1) {
xTaskNotifyWait(
0x00000000, // 接收通知前是否清楚通知值,按位,全为0表示不不清楚
0xffffffff, // 接收通知后是否要清楚通知值,按位,全为f表示清楚
&res_notify, // 接受值存放地址
portMAX_DELAY // 等待时间
);
sprintf(str, "task2 notify: %0x\r\n", res_notify);
UartSendData(str);
}
}

12、软件定时器

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include "main.h"
#include <stdint.h>


void StartTask(void);
void Task1(void);
void FreeRTOS_Start(void);

int main(void)
{
// 初始化HAL库函数必须要调用此函数
HAL_Init();
// 系统时钟即AHB/APB时钟配置
SystemClock_Config();
// 初始化LED
LedInit();
KeyInit();
UartInit(115200);
FreeRTOS_Start();
}

/* 任务句柄,用以保存不同任务的配置 */
TaskHandle_t start_task_handle;
TaskHandle_t task1_handle;


/*
* 函数作用:常规写法,起始任务,用以创建其他任务
* 输入参数:无
* 返回值:无
* 作者:LSK
*/
void FreeRTOS_Start(void)
{
xTaskCreate(
(TaskFunction_t) StartTask, //任务函数的地址
(char *) "StartTask", //任务函数的名称
(uint16_t) 128, //任务函数栈空间大小
(void *) NULL, //任务函数的参数
(UBaseType_t) 1, //任务函数的优先级
(TaskHandle_t*) &start_task_handle //任务函数的句柄
);

/* 启用调度器,负责任务切换*/
vTaskStartScheduler();

}
char str[100];

void TimerCallBack_1(TimerHandle_t timer);

TimerHandle_t timer_handle_1;

/*
* 函数作用:开始任务回调函数
* 输入参数:无
* 返回值:无
* 作者:LSK
*/
void StartTask(void)
{
/* 创建软件定时器,由软件定时器任务(通过定义宏,由系统创建)控制*/
timer_handle_1 = xTimerCreate("time_1", // 创建名称
500, // 定时器延迟时间
pdTRUE, // 是否重载(周期/一次)
(void *)1, // 定时器唯一ID
TimerCallBack_1 // 定时器回调函数
);

/* 进入临界保护区,保证在临界区的代码不会被打断*/
taskENTER_CRITICAL();
xTaskCreate((TaskFunction_t)Task1, (char *)"Task1", (uint16_t)128,
(void *)NULL, (UBaseType_t)3, (TaskHandle_t *)&task1_handle);

vTaskDelete(NULL); // 删除任务本身
/* 退出临界保护区*/
taskEXIT_CRITICAL();
}

/*
* 函数作用:开启软件定时器
* 输入参数:无
* 返回值:无
* 作者:LSK
*/
void Task1(void)
{
EventBits_t res;
while (1) {
if (KeyScan() == KEY0) {
/* 开启软件定时器*/
xTimerStart(timer_handle_1, // 定时器句柄
portMAX_DELAY); // 等待时间
UartSendData(("timer start!\r\n"));
}
vTaskDelay(200);
}
}

/*
* 函数作用:定时器回调函数
* 输入参数:定时器句柄
* 返回值:无
* 作者:LSK
*/
void TimerCallBack_1(TimerHandle_t timer)
{
if(timer == timer_handle_1)
{
UartSendData("Call back!\r\n");
LED_TOGGLE(LED0_GPIO_PORT, LED0_GPIO_PIN);
}
}