1.本文是利用FreeRTOS来动态创建任务和删除任务。主要是使用FreeRTOS的两个API函数:xTaskCreate()和vTaskDelete()。
任务1和任务2是让LED0、LED1闪烁。任务3是当按键按下时删除任务1。
使用动态创建任务时,需要动态的堆中申请任务所需的内存空间,所以首先需要将FreeRTOS.h中的宏定义(configSUPPORT_DYNAMIC_ALLOCATION)设置为1。
使用vTaskDelete()时需要将如下宏定义设置为1:
2.xTaskCreate()函数的6个参数参数说明:
任务优先级对应的数值越大,其优先级越高。任务句柄是相当于任务的身份证(ID),以方便其他函数通过任务句柄对其进行操作,比如vTaskDelete()中传入的任务句柄,即为删除任务句柄所对应的任务。
3.vTaskDelete()函数的参数说明:
当传入的参数为NULL,表述删除当前正在运行的任务。
4.代码:
(1)main.c:
#include "stm32f10x.h"
#include "led.h"
//#include "delay.h"
#include "FreeRTOS.h"
#include "task.h"
#include "key.h"
#include "sys.h"
//¶¨Òåstart_taskµÄÅäÖã¬ÈÎÎñ¾ä±ú£¬ÈÎÎñÓÅÏȼ¶£¬¶ÑÕ»´óС£¬ÈÎÎñÉùÃ÷£º
#define START_TASK_PRIO 1
#define START_TASK_STACK_SIZE 64
TaskHandle_t start_handler;
void start_task(void);
//¶¨ÒåÈÎÎñ1µÄÅäÖã¬ÈÎÎñ¾ä±ú£¬ÈÎÎñÓÅÏȼ¶£¬¶ÑÕ»´óС£¬ÈÎÎñÉùÃ÷£º
#define LED0_TASK_PRIO 2
#define LED0_TASK_STACK_SIZE 64
TaskHandle_t led0_handler;
void led0(void);
//¶¨ÒåÈÎÎñ2µÄÅäÖã¬ÈÎÎñ¾ä±ú£¬ÈÎÎñÓÅÏȼ¶£¬¶ÑÕ»´óС£¬ÈÎÎñÉùÃ÷£º
#define LED1_TASK_PRIO 3
#define LED1_TASK_STACK_SIZE 64
TaskHandle_t led1_handler;
void led1(void);
//¶¨ÒåÈÎÎñ2µÄÅäÖã¬ÈÎÎñ¾ä±ú£¬ÈÎÎñÓÅÏȼ¶£¬¶ÑÕ»´óС£¬ÈÎÎñÉùÃ÷£º
#define KEY_TASK_PRIO 4
#define KEY_TASK_STACK_SIZE 64
TaskHandle_t key_handler;
void key_task(void);
int flag = 0;
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// ÉèÖÃÖжÏÓÅÏȼ¶·Ö×é2
LED_Init();
KEY_Init();
xTaskCreate((TaskFunction_t) start_task, //ÈÎÎñº¯Êý
(const char *)"start_task", //ÈÎÎñÃû³Æ
(uint16_t)START_TASK_STACK_SIZE, //ÈÎÎñ¶ÑÕ»´óС
(void *)NULL, //´«µÝ¸øÈÎÎñº¯ÊýµÄ²ÎÊý
(UBaseType_t)START_TASK_PRIO, //ÈÎÎñÓÅÏȼ¶
(TaskHandle_t *)&start_handler); //ÈÎÎñ¾ä±ú
vTaskStartScheduler(); //¿ªÊ¼ÈÎÎñµ÷¶È
}
/*´´½¨¿ªÊ¼ÈÎÎñ£º*/
void start_task(void)
{
// taskENTER_CRITICAL();
/*´´½¨ÈÎÎñ*/
if(flag == 0)
{
xTaskCreate((TaskFunction_t) led0, //ÈÎÎñº¯Êý
(const char *)"led0_task", //ÈÎÎñÃû³Æ
(uint16_t)LED0_TASK_STACK_SIZE, //ÈÎÎñ¶ÑÕ»´óС
(void *)NULL, //´«µÝ¸øÈÎÎñº¯ÊýµÄ²ÎÊý
(UBaseType_t)LED0_TASK_PRIO, //ÈÎÎñÓÅÏȼ¶
(TaskHandle_t *)&led0_handler); //ÈÎÎñ¾ä±ú
xTaskCreate((TaskFunction_t) led1,
(const char *)"led1_task",
(uint16_t)LED1_TASK_STACK_SIZE,
(void *)NULL,
(UBaseType_t)LED1_TASK_PRIO,
(TaskHandle_t *)&led1_handler);
xTaskCreate((TaskFunction_t) key_task,
(const char *)"key_task",
(uint16_t)KEY_TASK_STACK_SIZE,
(void *)NULL,
(UBaseType_t)KEY_TASK_PRIO,
(TaskHandle_t *)&key_handler);
flag = 1;
}
vTaskDelay(500);
vTaskDelete(NULL); //ɾ³ýµ±Ç°ÈÎÎñ
// taskEXIT_CRITICAL();
}
void led0(void)
{
while(1)
{
GPIO_ResetBits(GPIOA,GPIO_Pin_8); //´ò¿ªLED
vTaskDelay(500);
//delay_ms(500);
GPIO_SetBits(GPIOA,GPIO_Pin_8); //´ò¿ªLED
vTaskDelay(500);
}
}
void led1(void)
{
while(1)
{
GPIO_ResetBits(GPIOD,GPIO_Pin_2); //´ò¿ªLED
vTaskDelay(500);
//delay_ms(500);
GPIO_SetBits(GPIOD,GPIO_Pin_2); //´ò¿ªLED
vTaskDelay(500);
}
}
/*´´½¨°´¼üÈÎÎñ£º*/
void key_task(void)
{
uint8_t key = 0;
while(1)
{
//printf("task3ÕýÔÚÔËÐУ¡£¡£¡\r\n");
//key = KEY_Scan(0);
if(KEY_0 == 0)
{
if(led0_handler != NULL)
{
//printf("ɾ³ýtask1ÈÎÎñ\r\n");
vTaskDelete(led0_handler);
led0_handler = NULL;
}
}
vTaskDelay(10);
}
}
(2)led.c和led.h:
#include "key.h"
#include "delay.h"
#include "led.h"
void KEY_Init(void)
{
/*1.¶¨ÒåÒý½ÅµÄ½á¹¹Ìå¡£
2.ʹÄÜÒý½Å¶ÔÓ¦µÄʱÖÓ¡£
3.ÅäÖÃÒý½ÅÐÅÏ¢*/
//¶¨ÒåÒý½Å½á¹¹Ì壺
GPIO_InitTypeDef GPIO_InitStruct;
//ʹÄÜʱÖÓ£º
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC,ENABLE);
//ÅäÖÃÒý½ÅÐÅÏ¢(KEY0)£º
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC,&GPIO_InitStruct);
//ÅäÖÃKEY1£º
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_15;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; //ÉèÖóÉÉÏÀÊäÈë
GPIO_Init(GPIOA,&GPIO_InitStruct);
//ÅäÖð´¼üWK_UP:
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD;
GPIO_Init(GPIOA,&GPIO_InitStruct);
}
void KEY_Scan(void)
{
static u8 key_up = 1; //°´¼üËÉ¿ª±ê־λ
if(key_up && (KEY_0 == 0|| KEY_1 == 0|| KEY_1 == 1))
{
//delay_ms(10); //È¥¶¶¶¯
key_up = 0;
if(KEY_0 == 0)
{
GPIO_ResetBits(GPIOD ,GPIO_Pin_2);
GPIO_SetBits(GPIOA,GPIO_Pin_8);
//delay_ms(1000);
}
else if(KEY_1 == 0)
{
GPIO_ResetBits(GPIOA ,GPIO_Pin_8);
GPIO_SetBits(GPIOD,GPIO_Pin_2);
//delay_ms(1000);
}
else if(KEY_2 == 1)
{
GPIO_ResetBits(GPIOA ,GPIO_Pin_8);
GPIO_ResetBits(GPIOD ,GPIO_Pin_2);
}
}
else if(KEY_0==1&&KEY_1==1&&KEY_2==0)
{
key_up = 1;
}
}
#ifndef __LED_H
#define __LED_H
#include "stm32f10x.h"
void LED_Init(void);
#endif
(3)key.c和key.h代码:
#include "key.h"
#include "delay.h"
#include "led.h"
void KEY_Init(void)
{
/*1.¶¨ÒåÒý½ÅµÄ½á¹¹Ìå¡£
2.ʹÄÜÒý½Å¶ÔÓ¦µÄʱÖÓ¡£
3.ÅäÖÃÒý½ÅÐÅÏ¢*/
//¶¨ÒåÒý½Å½á¹¹Ì壺
GPIO_InitTypeDef GPIO_InitStruct;
//ʹÄÜʱÖÓ£º
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC,ENABLE);
//ÅäÖÃÒý½ÅÐÅÏ¢(KEY0)£º
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC,&GPIO_InitStruct);
//ÅäÖÃKEY1£º
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_15;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; //ÉèÖóÉÉÏÀÊäÈë
GPIO_Init(GPIOA,&GPIO_InitStruct);
//ÅäÖð´¼üWK_UP:
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD;
GPIO_Init(GPIOA,&GPIO_InitStruct);
}
void KEY_Scan(void)
{
static u8 key_up = 1; //°´¼üËÉ¿ª±ê־λ
if(key_up && (KEY_0 == 0|| KEY_1 == 0|| KEY_1 == 1))
{
//delay_ms(10); //È¥¶¶¶¯
key_up = 0;
if(KEY_0 == 0)
{
GPIO_ResetBits(GPIOD ,GPIO_Pin_2);
GPIO_SetBits(GPIOA,GPIO_Pin_8);
//delay_ms(1000);
}
else if(KEY_1 == 0)
{
GPIO_ResetBits(GPIOA ,GPIO_Pin_8);
GPIO_SetBits(GPIOD,GPIO_Pin_2);
//delay_ms(1000);
}
else if(KEY_2 == 1)
{
GPIO_ResetBits(GPIOA ,GPIO_Pin_8);
GPIO_ResetBits(GPIOD ,GPIO_Pin_2);
}
}
else if(KEY_0==1&&KEY_1==1&&KEY_2==0)
{
key_up = 1;
}
}
#ifndef __KEY_H
#define __KEY_H
#include "stm32f10x.h"
#define KEY_0 GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_5) //¶ÁÈ¡°´¼üµÄ״̬
#define KEY_1 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_15)
#define KEY_2 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)
void KEY_Init(void);
void KEY_Scan(void); //°´¼üɨÃ躯Êý
#endif
(3)delay代码:
#include "delay.h"
static uint16_t fac_ms = 8;
extern void xPortSysTickHandler(void);
//systickÖжϷþÎñº¯Êý,ʹÓÃucosʱÓõ½
void SysTick_Handler(void)
{
if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//ϵͳÒѾÔËÐÐ
{
xPortSysTickHandler();
}
}
void delay_us(uint32_t us)
{
uint32_t i;
//1.Ñ¡ÔñHCLKʱÖÓ£¬²¢ÉèÖõδðʱÖÓ¼ÆÊýÖµ
SysTick_Config(72);
for(i = 0;i < us;i++)
{
while(!((SysTick->CTRL) & (1 << 16))); //µÈ´ý¼ÆÊýÍê³É
}
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //Ñ¡ÔñSTCLKʱÖÓÔ´£¬²¢Ê§Äܶ¨Ê±Æ÷
}
void delay_ms(u32 nms)
{
if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//ϵͳÒѾÔËÐÐ
{
if(nms>=fac_ms) //ÑÓʱµÄʱ¼ä´óÓÚOSµÄ×îÉÙʱ¼äÖÜÆÚ
{
vTaskDelay(nms/fac_ms); //FreeRTOSÑÓʱ
}
nms%=fac_ms; //OSÒѾÎÞ·¨ÌṩÕâôСµÄÑÓʱÁË,²ÉÓÃÆÕͨ·½Ê½ÑÓʱ
}
delay_us((u32)(nms*1000)); //ÆÕͨ·½Ê½ÑÓʱ
}
void delay_xms(uint32_t ms) //·â×°ÈÎÎñÇл»µÄÑÓʱº¯Êý
{
if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) //Èç¹ûϵͳÒѾÔÚÔËÐУ¬Ôò¿ªÊ¼ÑÓʱ
{
if(ms >= fac_ms)
{
vTaskDelay(ms / fac_ms);
}
ms %= fac_ms; //µ±OSÎÞ·¨ÌṩÕâôСµÄÑÓʱʱ£¬Ê¹ÓÃÆÕͨÑÓʱ
}
delay_ms((uint32_t)(ms*1000)); //ÆÕͨÑÓʱ
}
#ifndef __DELAY_H
#define __DELAY_H
#include "stm32f10x.h"
#include "FreeRTOS.h"
#include "task.h"
void delay_us(uint32_t us); //ÑÓʱ΢Ãë
void delay_ms(uint32_t ms); //ÑÓʱºÁÃë
void delay_xms(uint32_t ms); //·â×°ÈÎÎñÇл»µÄÑÓʱº¯Êý
#endif
5.运行结果:
6.总结:
动态创建任务是系统自动分配内存,设置好相关的宏定义后,直接对应函数API即可。删除任务时也是利用API函数去完成。
在做本文实验,一开始每当按下按键时,程序就跑飞了。后面才发现,用来是按键部分的延时有问题。当时移植FreeRTOS后,delay部分的延时函数需要进行修改。本文为了方便实验,取消了按键的防止抖动延时。此处需要注意,当需要使用非FreeRTOS的延时函数时,一定要配置好新的delay延时函数。