一、创建任务
1.本例程思路:
1). 调用 xTaskCreateStatic 函数静态创建任务 LED_Task;
LED_Task 控制 LED 每间隔一段时间翻转一次
2). 调用 xTaskCreate 函数动态创建任务 AppTaskCreate_Task;
AppTaskCreate_Task 动态创建任务 LED_Task 与 LED2_Task;
LED_Task 与 LED2_Task 分别控制 LED 与 LED2 每隔一段时间翻转一次
本篇将静态创建与动态创建写入同一段代码,使用 _USE_STATIC_MODE 与 _USE_DYNAMIC_MODE 进行区分
其中,
动态创建方式,初始化相关资源(中断, GPIO等)后,直接调用任务创建函数 xTaskCreate 创建任务,随后开启任务调度器即可(任务函数执行的内容自行实现);
而静态创建方式,需要手动开辟存储空间(任务堆栈, 任务控制块,包括IdleTask与TimerTask),随后可以直接调用 xTaskCreateStatic 函数创建任务,调用 vTaskStartScheduler 函数开启任务调度器
启动任务调度器后,任务调度器会自动创建一个IdleTask任务,以保证始终能有一个任务在运行,所以使用静态方式创建任务时需要手动为IdleTask分配空间(实现 vApplicationGetIdleTaskMemory 函数)
2.代码编写
#include "stm32f10x.h"
#include "dr_usart.h"
#include "dr_led.h"
#include "FreeRTOS.h"
#include "task.h"
#if defined(_USE_STATIC_MODE)
#define USER_DEFAULT_STACK_SIZE ((unsigned short)128) //任务堆栈大小
StackType_t Idle_Task_Stack[USER_DEFAULT_STACK_SIZE]; //
StaticTask_t Idle_Task_TCB; //
StackType_t Timer_Task_Stack[USER_DEFAULT_STACK_SIZE]; //
StaticTask_t Timer_Task_TCB; //
StackType_t LED_Task_Stack[USER_DEFAULT_STACK_SIZE]; //
StaticTask_t LED_Task_TCB; //
TaskHandle_t LED_Task_Handle;
void LED_Task(void *);
#endif
#if defined(_USE_DYNAMIC_MODE)
void AppTaskCreate_Task(void *);
void LED_Task(void *);
void LED2_Task(void *);
#endif
int main(void)
{
NVIC_Priority_Group_Config();
USART1_Config();
LED_GPIO_Config();
#if defined(_USE_STATIC_MODE)
LED_Task_Handle = xTaskCreateStatic( LED_Task, //指向任务函数
"LED_Task", //任务名称
USER_DEFAULT_STACK_SIZE, //任务堆栈大小
(void *)NULL, 1, //任务参数, 任务优先级
LED_Task_Stack, //任务堆栈地址
&LED_Task_TCB ); //任务控制块地址
#endif
#if defined(_USE_DYNAMIC_MODE)
xTaskCreate(AppTaskCreate_Task, "AppTaskCreate_Task", 128, NULL, 1, NULL);
#endif
vTaskStartScheduler();
while(1);
}
#if defined(_USE_DYNAMIC_MODE)
void AppTaskCreate_Task(void *pvParameters)
{
taskENTER_CRITICAL();
xTaskCreate(LED_Task, "LED_Task", 128, NULL, 2, NULL);
xTaskCreate(LED2_Task, "LED2_Task", 128, NULL, 3, NULL);
vTaskDelete(NULL);
taskEXIT_CRITICAL();
}
#endif
void LED_Task(void *pvParameters)
{
for(;;)
{
GPIOA->ODR ^= ((uint16_t)0x0100);
vTaskDelay(50);
}
}
#if defined(_USE_DYNAMIC_MODE)
void LED2_Task(void *pvParameters)
{
for(;;)
{
GPIOA->ODR ^= ((uint16_t)0x0040);
vTaskDelay(50);
}
}
#endif
#if defined(_USE_STATIC_MODE)
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer,
StackType_t **ppxIdleTaskStackBuffer,
uint32_t *pulIdleTaskStackSize )
{
*ppxIdleTaskTCBBuffer = &Idle_Task_TCB; //指向任务控制块
*ppxIdleTaskStackBuffer = Idle_Task_Stack; //指向任务堆栈
*pulIdleTaskStackSize = USER_DEFAULT_STACK_SIZE; //任务堆栈大小
}
void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer,
StackType_t **ppxTimerTaskStackBuffer,
uint32_t *pulTimerTaskStackSize )
{
*ppxTimerTaskTCBBuffer = &Timer_Task_TCB;
*ppxTimerTaskStackBuffer = Timer_Task_Stack;
*pulTimerTaskStackSize = USER_DEFAULT_STACK_SIZE;
}
#endif
3.调用逻辑分析仪观察(动态时,两个LED应同时翻转)
静态创建(任务:LED_Task)
动态创建(任务:LED_Task,LED2_Task)
经验证,程序运行结果与预想一致
二、任务挂起与恢复
1.本例程思路:
分别创建两个任务,LEDTask 与 KEYTask,LEDTask 控制 LED 每隔一段时间翻转一次,KEYTask 检测 KEY_GPIO(PA0) 的状态,第一次出现下降沿时调用 vTaskSuspend 函数挂起 LEDTask,第二次出现下降时调用 vTaskResume 函数沿恢复 LEDTask,依次循环
2.代码编写
#include "stm32f10x.h"
#include "dr_usart.h"
#include "dr_led.h"
#include "dr_key.h"
#include "FreeRTOS.h"
#include "task.h"
TaskHandle_t LEDTask_Handle = NULL;
void AppTaskCreateTask(void *);
void LEDTask(void *);
void KEYTask(void *);
int main(void)
{
NVIC_Priority_Group_Config();
USART1_Config();
LED_GPIO_Config();
KEY_GPIO_Config();
xTaskCreate(AppTaskCreateTask, "AppTaskCreateTask", 128, NULL, 1, NULL);
vTaskStartScheduler();
while(1);
}
void AppTaskCreateTask(void *pvParameters)
{
taskENTER_CRITICAL();
xTaskCreate(LEDTask, "LEDTask", 128, NULL, 2, &LEDTask_Handle);
xTaskCreate(KEYTask, "KEYTask", 128, NULL, 3, NULL);
vTaskDelete(NULL);
taskEXIT_CRITICAL();
}
void LEDTask(void *pvParameters)
{
for (;;)
{
GPIOA->ODR ^= ((uint16_t)0x0100);
printf("LED %srn", ((GPIOA->IDR & 0x0100) != 0) ? "is running." : "stops running.");
vTaskDelay(50);
}
}
void KEYTask(void *pvParameters)
{
uint8_t level_high = 0;
uint8_t level_low = 0;
uint8_t edge_fall = 0;
uint8_t edge_rise = 0;
uint8_t _switch = 0;
for (;;)
{
if ( (GPIOA->IDR & 0x0001) != 0 )
{
if(level_low == 1)
edge_rise = 1;
level_low = 0;
level_high = 1;
}
if ( (GPIOA->IDR & 0x0001) == 0 )
{
if(level_high == 1)
edge_fall = 1;
level_high = 0;
level_low = 1;
}
if(edge_fall)
{
if(_switch == 0)
{
_switch = 1;
printf("--- Suspend ---.n");
vTaskSuspend(LEDTask_Handle);
}
else
{
_switch = 0;
printf("--- Resume ---.n");
vTaskResume(LEDTask_Handle);
}
}
edge_fall = 0;
edge_rise = 0;
(void)edge_rise;
vTaskDelay(20);
}
}
3.调用逻辑分析仪观察
经验证,程序运行结果与预想一致



