任务挂起和任务恢复API函数解析
- 1:根据任务句柄来挂起任务控制块,如果任务句柄为NULL表示要挂起任务自身
- 2:将要挂起的任务从相应的状态列表中移除
- 3:判断任务调度器是否在运行,如果在运行,更新下一次阻塞时间,防止被挂起任务为下一次阻塞超时
- 4:如果挂起的是任务自身 【调度器正在运行,强制进行一次任务切换】,调度器没有运行【是:代表任务均被挂起,则当前的控制块赋值为NULL】【否:通过函数vTaskSwitchContext寻找下一个最高优先级任务】
实现功能简介
创建一个头文件进行宏定义和函数声明(TaskHead.h)
#ifndef __TASKHEADE_H_
#define __TASKHEADE_H_
// 任务堆栈深度
#define STACK_TASK_DEPTH 128
// 优先级
#define STACK_TASK_PRIO 1
// 任务句柄
TaskHandle_t TASK_BEGIN_HANDLE;
// 任务堆栈深度
#define KEY_TASK_DEPTH 128
// 优先级
#define KEY_TASK_PRIO 2
// 任务句柄
TaskHandle_t KEY_HANDLE;
// 任务堆栈深度
#define TASK1_TASK_DEPTH 128
// 优先级
#define TASK1_TASK_PRIO 3
// 任务句柄
TaskHandle_t TASK1_HANDLE;
// 任务堆栈深度
#define TASK2_TASK_DEPTH 128
// 优先级
#define TASK2_TASK_PRIO 4
// 任务句柄
TaskHandle_t TASK2_HANDLE;
void start_task(void * pram);
void key_task(void *pram);
void task1(void *pram);
void task2(void *pram);
#endif
使用FreeRTOS动态创建任务
int main(void){
xTaskCreate(
(TaskFunction_t ) start_task,
( char * ) "start_task",
(uint16_t ) STACK_TASK_DEPTH,
(void * ) NULL,
(UBaseType_t ) STACK_TASK_PRIO,
(TaskHandle_t * ) &TASK_BEGIN_HANDLE );
// 开始任务
vTaskStartScheduler();
while(1){
}
return 0;
}
start_task任务创建
// 创建开始任务
void start_task(void * pram){
taskENTER_CRITICAL(); //进入临界区
xTaskCreate(
(TaskFunction_t ) key_task,
( char * ) "key_task",
(uint16_t ) KEY_TASK_DEPTH,
(void * ) NULL,
(UBaseType_t ) KEY_TASK_PRIO,
(TaskHandle_t * ) &KEY_HANDLE );
xTaskCreate(
(TaskFunction_t ) task1,
( char * ) "task1",
(uint16_t ) TASK1_TASK_DEPTH,
(void * ) NULL,
(UBaseType_t ) TASK1_TASK_PRIO,
(TaskHandle_t * ) &TASK1_HANDLE );
xTaskCreate(
(TaskFunction_t ) task2,
( char * ) "task2",
(uint16_t ) TASK2_TASK_DEPTH,
(void * ) NULL,
(UBaseType_t ) TASK2_TASK_PRIO,
(TaskHandle_t * ) &TASK2_HANDLE );
//删除开始时任务
vTaskDelete(TASK_BEGIN_HANDLE);
// 退出临界区
taskEXIT_CRITICAL();
}
任务实现函数:创建的FreeRTOS任务需要做的事情
// 创建任务函数
void key_task(void *pram){
LED_Init();
Key_Init();
while (1)
{
// 直接把函数放在main函数中获取键码值的时候起效果了
if (GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) == 0) //按键1按下
{
vTaskDelay(10); // 延时消除抖动
// 将按键挂起
vTaskSuspend(TASK1_HANDLE);
}
if (GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11) == 0) //按键2按下
{
vTaskDelay(10); // 延时消除抖动
// 将按键唤醒
vTaskResume(TASK1_HANDLE);
}
}
vTaskDelay(10); //延时10ms
}
// 创建任务函数
void task1(void *pram){
LED_Init();
while(1){
LED1_Turn();
vTaskDelay(30);
}
}
// 创建任务函数
void task2(void *pram){
LED_Init();
while(1){
LED2_Turn();
vTaskDelay(30);
}
}
main函数所有代码
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "freeRTOS.h"
#include "task.h"
#include "LED.h"
#include "TaskHead.h"
#include "KEY.h"
int main(void){
xTaskCreate(
(TaskFunction_t ) start_task,
( char * ) "start_task",
(uint16_t ) STACK_TASK_DEPTH,
(void * ) NULL,
(UBaseType_t ) STACK_TASK_PRIO,
(TaskHandle_t * ) &TASK_BEGIN_HANDLE );
// 开始任务
vTaskStartScheduler();
while(1){
}
return 0;
}
// 创建开始任务
void start_task(void * pram){
taskENTER_CRITICAL(); //进入临界区
xTaskCreate(
(TaskFunction_t ) key_task,
( char * ) "key_task",
(uint16_t ) KEY_TASK_DEPTH,
(void * ) NULL,
(UBaseType_t ) KEY_TASK_PRIO,
(TaskHandle_t * ) &KEY_HANDLE );
xTaskCreate(
(TaskFunction_t ) task1,
( char * ) "task1",
(uint16_t ) TASK1_TASK_DEPTH,
(void * ) NULL,
(UBaseType_t ) TASK1_TASK_PRIO,
(TaskHandle_t * ) &TASK1_HANDLE );
xTaskCreate(
(TaskFunction_t ) task2,
( char * ) "task2",
(uint16_t ) TASK2_TASK_DEPTH,
(void * ) NULL,
(UBaseType_t ) TASK2_TASK_PRIO,
(TaskHandle_t * ) &TASK2_HANDLE );
//删除开始时任务
vTaskDelete(TASK_BEGIN_HANDLE);
// 退出临界区
taskEXIT_CRITICAL();
}
// 创建任务函数
void key_task(void *pram){
LED_Init();
Key_Init();
while (1)
{
// 直接把函数放在main函数中获取键码值的时候起效果了
if (GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) == 0) //按键1按下
{
vTaskDelay(10); // 延时消除抖动
// 将按键挂起
vTaskSuspend(TASK1_HANDLE);
}
if (GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11) == 0) //按键2按下
{
vTaskDelay(10); // 延时消除抖动
// 将按键唤醒
vTaskResume(TASK1_HANDLE);
}
}
vTaskDelay(10); //延时10ms
}
// 创建任务函数
void task1(void *pram){
LED_Init();
while(1){
LED1_Turn();
vTaskDelay(30);
}
}
// 创建任务函数
void task2(void *pram){
LED_Init();
while(1){
LED2_Turn();
vTaskDelay(30);
}
}
两个LED灯产生的PWM波形
当一个按键被按下的时候TASK1任务会被挂起,当按下第二个按键的时候第二个任务会被挂起