FreeRTOS例程1-基础任务创建

举报
码农爱学习 发表于 2021/08/15 14:48:32 2021/08/15
【摘要】 本篇就来开始进行FreeRTOS的编程实践,实现基础的任务创建功能。

上篇文章介绍FreeRTOS的源码结构,以及如何将FreeRTOS移植到STM32F407单片机中,本篇就来开始进行FreeRTOS的编程实践。

FreeRTOS是多任务系统,首先就要先来进程任务的创建,以简单的LED灯任务为例。

1 API函数

1.1 任务创建 xTaskCreate()

函数原型(tasks.c中):

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:任务堆栈大小(实际上申请到的是这里的4倍),设的太小任务可能无法运行!

  • pvParameters:任务函数的参数,不需要传参设为NULL即可

  • uxPriority:任务优先级,0~(configMAX_PRIORITIES-1)

  • pxCreatedTask:任务句柄,实际是一个指针,也是任务的任务堆栈

返回值:

  • pdPASS:数值1,任务创建成功,且添加到就绪列表

  • 错误代码:负数,任务创建识别

这里的返回值是BaseType_t,实际它是long类型,可以在portmacro.h文件中看到其定义:

typedef long BaseType_t;

另外,任务句柄的类型为TaskHandle_t,实际它是void *类型,可以在task.h文件中看到其定义:

typedef void * TaskHandle_t;

注:xTaskCreate()是一种动态创建任务的方式,系统通过heap_4.c的配置为任务自动分配相关内存,还有一种静态创建任务的方式xTaskCreateStatic(),这里先不介绍。

1.2 任务删除 vTaskDelete()

函数原型(tasks.c中):

void vTaskDelete( TaskHandle_t xTaskToDelete )

参数:

  • xTaskToDelete:要删除的任务的任务句柄

注:通过 xTaskCreate()动态创建的任务,在使用vTaskDelete()删除后,该任务创建时申请的堆栈和内存会在系统的空闲任务中被释放掉。

1.3 任务调度 vTaskStartScheduler()

函数原型(tasks.c中):

void vTaskStartScheduler( void )

不需要参数,开启后就由FreeRTOS开始任务调度工作。

2 程序设计

2.1 主函数

主函数还是我们熟悉的main函数,但FreeRTOS里的main函数不需要自己设计成死循环,只需要创建任务并开启任务调度,即可使系统持续运行。

任务的创建一般都是先创建一个开始任务,然后开始任务再负责创建其它子任务。

int main(void)
{ 
    //设置系统中断优先级分组4(FreeRTOS中的默认方式!)
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
    
    //初始化LED端口
    LED_Init();                         
​
    //创建开始任务
    xTaskCreate((TaskFunction_t )start_task,            //任务函数
                (const char*    )"start_task",          //任务名称
                (uint16_t       )START_STK_SIZE,        //任务堆栈大小
                (void*          )NULL,                  //传递给任务函数的参数
                (UBaseType_t    )START_TASK_PRIO,       //任务优先级
                (TaskHandle_t*  )&StartTask_Handler);   //任务句柄  
    //开启任务调度                
    vTaskStartScheduler();          
}

2.2 开始任务函数

开始任务函数的功能就是用来创建其它的子任务,创建完之后会把自己删除掉。

//开始任务任务函数
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           //进入临界区
    
    //创建TASK1任务
    xTaskCreate((TaskFunction_t )task1_task,             
                (const char*    )"task1_task",           
                (uint16_t       )TASK1_STK_SIZE,        
                (void*          )NULL,                  
                (UBaseType_t    )TASK1_TASK_PRIO,        
                (TaskHandle_t*  )&Task1Task_Handler);   
    //创建TASK2任务
    xTaskCreate((TaskFunction_t )task2_task,     
                (const char*    )"task2_task",   
                (uint16_t       )TASK2_STK_SIZE,
                (void*          )NULL,
                (UBaseType_t    )TASK2_TASK_PRIO,
                (TaskHandle_t*  )&Task2Task_Handler); 
                
    vTaskDelete(StartTask_Handler); //删除开始任务
                
    taskEXIT_CRITICAL();            //退出临界区
}

2.3 两个任务函数

每个任务函数都是一个死循环,注意循环中必须添加vTaskDelay()延时函数,用于任务的切换。

//task1任务函数
void task1_task(void *pvParameters)
{
    while(1)
    {
        LEDa_Toggle;
        vTaskDelay(500); //延时500ms
    }
}
​
//task2任务函数
void task2_task(void *pvParameters)
{
    while(1)
    {
        LEDb_ON;
        vTaskDelay(200); //延时200ms
        LEDb_OFF;
        vTaskDelay(800); //延时800ms
    }
}

2.4 main.c所有程序

#include "stm32f4xx.h"
#include "led.h"
​
#include "FreeRTOS.h"
#include "task.h"
​
//任务参数--------------------------
//优先级 堆栈大小 任务句柄 任务函数
#define START_TASK_PRIO     1
#define START_STK_SIZE      128  
TaskHandle_t StartTask_Handler;
void start_task(void *pvParameters);
​
#define TASK1_TASK_PRIO     2
#define TASK1_STK_SIZE      128  
TaskHandle_t Task1Task_Handler;
void task1_task(void *pvParameters);
​
#define TASK2_TASK_PRIO     3   
#define TASK2_STK_SIZE      128  
TaskHandle_t Task2Task_Handler;
void task2_task(void *pvParameters);
​
​
int main(void)
{ 
    //设置系统中断优先级分组4(FreeRTOS中的默认方式!)
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
    
    //初始化LED端口
    LED_Init();                         
​
    //创建开始任务
    xTaskCreate((TaskFunction_t )start_task,            //任务函数
                (const char*    )"start_task",          //任务名称
                (uint16_t       )START_STK_SIZE,        //任务堆栈大小
                (void*          )NULL,                  //传递给任务函数的参数
                (UBaseType_t    )START_TASK_PRIO,       //任务优先级
                (TaskHandle_t*  )&StartTask_Handler);   //任务句柄  
    //开启任务调度                
    vTaskStartScheduler();          
}
​
//开始任务任务函数
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           //进入临界区
    
    //创建TASK1任务
    xTaskCreate((TaskFunction_t )task1_task,             
                (const char*    )"task1_task",           
                (uint16_t       )TASK1_STK_SIZE,        
                (void*          )NULL,                  
                (UBaseType_t    )TASK1_TASK_PRIO,        
                (TaskHandle_t*  )&Task1Task_Handler);   
    //创建TASK2任务
    xTaskCreate((TaskFunction_t )task2_task,     
                (const char*    )"task2_task",   
                (uint16_t       )TASK2_STK_SIZE,
                (void*          )NULL,
                (UBaseType_t    )TASK2_TASK_PRIO,
                (TaskHandle_t*  )&Task2Task_Handler); 
                
    vTaskDelete(StartTask_Handler); //删除开始任务
                
    taskEXIT_CRITICAL();            //退出临界区
}
​
//task1任务函数
void task1_task(void *pvParameters)
{
    while(1)
    {
        LEDa_Toggle;
        vTaskDelay(500); //延时500ms
    }
}
​
//task2任务函数
void task2_task(void *pvParameters)
{
    while(1)
    {
        LEDb_ON;
        vTaskDelay(200); //延时200ms
        LEDb_OFF;
        vTaskDelay(800); //延时800ms
    }
}

3 运行结果

运行效果是板子上的两个LED按照各自任务函数中设定的亮灭时间不断闪烁。

使用系统的原因就是可以让两个任务看起来像是同时运行,试想,如果是裸机系统,虽然也可以实现同样功能(这两个LED任务的闪烁规律比较简单),但需要将两个任务结合起来管理亮灭时间,两个任务就纠缠在一起了,如果是两个更复杂的任务,裸机系统可能就无法实现了。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。