目录
一、任务创建
1.动态创建任务xTaskCreate( )
函数原型:
BaseType_t xTaskCreate(
TaskFunction_t
pxTaskCode
,
const char *
const pcName
,
const uint16_t
usStackDepth
,
void * const
pvParameters
,
UBaseType_t
uxPriority
,
TaskHandle_t *
const pxCreatedTask
);
参数:
pxTaskCode
: 任务函数。
pcName
: 任务名字,一般用于追踪和调试。
usStackDepth
: 任务堆栈大小,实际申请到的堆栈是
usStackDepth
的
4
倍。
pvParameters:
传递给任务函数的参数。
uxPriotiry:
任务优先级,范围
0~ configMAX_PRIORITIES-1
。
pxCreatedTask:
任务控制块,又叫任务句柄,包含创建任务的所有信息。
返回值:
pdPASS:
任务创建成功
errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY
: 任务创建失败,因为堆内
存不足!
完整动态创建一个任务代码:
//任务优先级
#define LED0_TASK_PRIO 3
//任务堆栈大小
#define LED0_STK_SIZE 50
//任务句柄
TaskHandle_t LED0Task_Handler;
//任务函数
void led0_task(void *pvParameters);
//创建LED0任务
xTaskCreate((TaskFunction_t )led0_task, //任务函数
(const char* )"led0_task", //任;务名称
(uint16_t )LED0_STK_SIZE,//任务堆栈大小
(void* )NULL, //传递给任务函数的参数
(UBaseType_t )LED0_TASK_PRIO,//任务优先级
(TaskHandle_t* )&LED0Task_Handler); //任务句柄
void led0_task(void *pvParameters)
{
u8 task0_num = 0;
while(1)
{
task0_num++;
LED0=!LED0;
printf("task_led0已经执行: %d次\r\n",task0_num);
vTaskDelay(1000);
}
}
2.静态创建任务xTaskCreateStatic()
函数原型:
TaskHandle_t xTaskCreateStatic(
TaskFunction_t
pxTaskCode,
const char *
const pcName,
const uint32_t
ulStackDepth,
void *
const pvParameters,
UBaseType_t
uxPriority,
StackType_t *
const puxStackBuffer,
StaticTask_t *
const pxTaskBuffer )
参数:
pxTaskCode
: 任务函数。
pcName
: 任务名字,一般用于追踪和调试
usStackDepth
: 任务堆栈大小,由于本函数是静态方法创建任务,所以任务堆
栈由用户给出,一般是个数组,此参数就是这个数组的大小。
pvParameters:
传递给任务函数的参数。
uxPriotiry:
任务优先级,范围
0~ configMAX_PRIORITIES-1
。
puxStackBuffer:
任务堆栈,一般为数组,数组类型要为
StackType_t
类型。
pxTaskBuffer:
任务控制块
.
返回值:
NULL
: 任务创建失败,
puxStackBuffer
或
pxTaskBuffer
为
NULL
的时候会导
致这个错误的发生
其他值
:
任务创建成功,
返回任务的任务句柄
注:一般不用静态创建
二、任务删除vTaskDelete
vTaskDelete()
:删除一个用函数
xTaskCreate()
或者
xTaskCreateStatic()
创建的任务,被删除了的任务不再存在,也就是说再也不会进入运行态。任务
被删除以后就不能再使用此任务的句柄!
示例:任务0删除任务1:
void led0_task(void *pvParameters)
{
vTaskDelay(10000);
if(LED1Task_Handler != NULL) //判断led1任务是否存在
{
vTaskDelete(LED1Task_Handler);//删除led1任务
LED1Task_Handler=NULL; //led1任务句柄清零
printf("led0任务删除了led1任务\r\n");
}
while(1)
{
LED0=!LED0;
vTaskDelay(1000);
}
}
//LED1任务函数
void led1_task(void *pvParameters)//创建10秒后被led0任务删除了
{
while(1)
{
printf("this is led1_task......\r\n");
LED1 = 1;
vTaskDelay(500);
LED1 = 0;
vTaskDelay(500);
}
}
三、任务的挂起、恢复
1.任务的挂起
当某个任务要停止运行一段时间的话就将这个任务挂起,当要重新运行这个任务的话就恢复这个任务的运行。
函数:
vTaskSuspend()
参数:要挂起任务的句柄,如果为NULL的话表示挂起任务自己
vTaskSuspend(LED0Task_Handler);
此函数用于将某个任务设置为挂起态,进入挂起态的
任务永远都不会进入运行态。退出挂起态的唯一方法就是调用任务恢复
函数
vTaskResume()或 xTaskResumeFromISR()
2.任务中恢复
函数:vTaskResume()
参数:要恢复的任务的任务句柄
3.任务从中断中恢复
函数:xTaskResumeFromISR()
参数:要恢复的任务的任务句柄
返回值:
pdTRUE:恢复的任务的任务优先级等于或者高于正在运行的任务(被中断打断的任务),这意味着在退出中断服务函数以后要进行一次上下文切换
pdFALSE:恢复的任务的任务优先级低于正在运行的任务(被中断打断的任务),这意味着在退出中断服务函数以后不需要进行一次上下文切换
测试代码:
按键扫描进行挂起任务,另外一个按键用中断的方式实现中断中恢复任务:
main.c
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"
#include "timer.h"
#include "key.h"
//任务优先级
#define LED0_TASK_PRIO 1
//任务堆栈大小
#define LED0_STK_SIZE 50
//任务句柄
TaskHandle_t LED0Task_Handler;
//任务函数
void led0_task(void *pvParameters);
//任务优先级
#define LED1_TASK_PRIO 2
//任务堆栈大小
#define LED1_STK_SIZE 50
//任务句柄
TaskHandle_t LED1Task_Handler;
//任务函数
void led1_task(void *pvParameters);
//任务优先级
#define KEY_TASK_PRIO 4
//任务堆栈大小
#define KEY_STK_SIZE 50
//任务句柄
TaskHandle_t KEYTask_Handler;
//任务函数
void key_task(void *pvParameters);
uint16_t sum1=0;
uint16_t sum2=0;
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4(freertos)
delay_init(); //延时函数初始化
uart_init(115200); //初始化串口
LED_Init(); //初始化LED
TIM3_Init(9999,7199);
KEY_Init();
//创建LED0任务
xTaskCreate((TaskFunction_t )led0_task, //任务函数
(const char* )"led0_task", //任;务名称
(uint16_t )LED0_STK_SIZE,//任务堆栈大小
(void* )NULL, //传递给任务函数的参数
(UBaseType_t )LED0_TASK_PRIO,//任务优先级
(TaskHandle_t* )&LED0Task_Handler); //任务句柄
//创建LED1任务
xTaskCreate((TaskFunction_t )led1_task,
(const char* )"led1_task",
(uint16_t )LED1_STK_SIZE,
(void* )NULL,
(UBaseType_t )LED1_TASK_PRIO,
(TaskHandle_t* )&LED1Task_Handler);
//创建KEY任务
xTaskCreate((TaskFunction_t )key_task,
(const char* )"key_task",
(uint16_t )KEY_STK_SIZE,
(void* )NULL,
(UBaseType_t )KEY_TASK_PRIO,
(TaskHandle_t* )&KEYTask_Handler);
vTaskStartScheduler(); //开启任务调度
/*
调度器并非自动运行的,需要人为启动它。 API函
数vTaskStartScheduler()用于启动调度器,它会创建一个空闲任务、初始化一些
静态变量,最主要的,它会初始化系统节拍定时器并设置好相应的中断,然后启
动第一个任务
*/
}
u8 KEY_scan(void)
{
static u8 key_up = 1;
if(key_up && ( KEY5==0 || KEY6==0))
{
delay_xms(20);
key_up = 0;
if(KEY5==0) return KEY5_PRESS;
else if(KEY6==0) return KEY6_PRESS;
}
else if (KEY5==1&&KEY6==1)
{
key_up=1;
return 0;
}
}
void key_task(void *pvParameters)
{
u8 key;
while(1)
{
key=KEY_scan();
switch(key)
{
case KEY5_PRESS:
printf("挂起任务led0\r\n");
vTaskSuspend(LED0Task_Handler);
break;
}
vTaskDelay(100);
}
}
void led0_task(void *pvParameters)
{
u8 task0_num = 0;
while(1)
{
task0_num++;
LED0=!LED0;
printf("task_led0已经执行: %d次\r\n",task0_num);
vTaskDelay(1000);
}
}
//LED1任务函数
void led1_task(void *pvParameters)//创建5秒后被led0任务删除了
{
u8 task1_num = 0;
while(1)
{
task1_num++;
LED1=!LED1;
delay_xms(2000);
printf("task_led1已经执行: %d次\r\n",task1_num);
delay_xms(1000);
vTaskDelay(30);
}
}
key.c
#include "stm32f10x.h"
#include "key.h"
#include "delay.h"
#include "usart.h"
#include "stdio.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"
extern TaskHandle_t LED0Task_Handler;
void KEY_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource4);
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //中断请求模式
EXTI_InitStructure.EXTI_Line = EXTI_Line4; //外部中断线
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //设置输入线路下降沿为中断请求
EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能
EXTI_Init(&EXTI_InitStructure);//初始化
NVIC_InitStructure.NVIC_IRQChannel =EXTI4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =6;//抢占优先级,>=5
NVIC_Init(&NVIC_InitStructure);
}
void EXTI4_IRQHandler(void)
{
BaseType_t YieldRequired;
if(EXTI_GetITStatus(EXTI_Line4)!=RESET)
{
delay_xms(100);
if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_4)==0)
{
YieldRequired=xTaskResumeFromISR(LED0Task_Handler);//恢复任务,返回值为pdTRUE或者pdFALSE
printf("恢复任务led0\r\n");
if(YieldRequired==pdTRUE)//如果恢复的任务优先级高于或等于正在运行的任务,则马上强制切换任务
{
portYIELD_FROM_ISR(YieldRequired);
}
}
EXTI_ClearITPendingBit(EXTI_Line4);//清除EXTI线路挂起位
}
}