FreeRTOS动态方法实现两个LED 灯闪烁

本文介绍使用FreeRTOS操作系统时如何通过动态内存分配方法创建任务。重点讲解了堆内存的初始化过程、动态创建任务的函数xTaskCreate()的使用方法,并提供了一个包含多个任务创建的完整示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在前面实验中,我们使用静态内存方法创建了 2 个任务,任务的栈,任务的 控制块用的都是静态内存,必须由用户预先定义,这种方法我们在使用 FreeRTOS 的时候用的比较少,通常的方法是使用动态内存方法创建任务,由系统自动分配 任务栈和控制块

1 动态内存分

在使用静态方法创建任务的例程中,任务控制块和任务栈的内存空间都是从 内部的 SRAM 里面分配的,具体分配到哪个地址由编译器决定。现在我们开始使 用动态内存,即堆,其实堆也是内存,也属于 SRAM。FreeRTOS 做法是在 SRAM 里 面定义一个大数组,也就是堆内存,供 FreeRTOS 的动态内存分配函数使用,在 第一次使用的时候,系统会将定义的堆内存进行初始化,这些代码在 FreeRTOS 提供的内存管理方案中实现(heap_1.c、heap_2.c、heap_4.c 等,具体的内存 管理方案后面详细讲解),具体见代码。

//系统所有总的堆大小
#define configTOTAL_HEAP_SIZE ((size_t)(36*1024))// (1)
static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];// (2)
/* 如果这是第一次调用 malloc 那么堆将需要初始化,以设置空闲块列表。*/
if ( pxEnd == NULL )
{
prvHeapInit(); (3)
}
else
{
mtCOVERAGE_TEST_MARKER();

代码(1):堆内存的大小为 configTOTAL_HEAP_SIZE ,在 FreeRTOSConfig.h 中由我们自己定义,configSUPPORT_DYNAMIC_ALLOCATION 这个宏定义在使用 FreeRTOS 操作系统的时候必须开启,且关闭 configSUPPORT_STATIC_ALLOCATION 这个宏。 代码(2):从内部 SRAMM 里面定义一个静态数组 ucHeap,大小由 configTOTAL_HEAP_SIZE 这个宏决定,目前定义为 36KB。定义的堆大小不能超 过内部 SRAM 的总大小。 代码(3):如果这是第一次调用 malloc 那么需要将堆进行初始化,以设置 空闲块列表,方便以后分配内存,初始化完成之后会取得堆的结束地址,在 MemMang 中的 5 个内存分配 heap_x.c 文件中实现。

2 动态创建任务函数

使用动态内存的时,使用 xTaskCreate()函数来创建任务。如下:

//创建开始任务
xTaskCreate((TaskFunction_t )start_task, //任务函数 (1)
(const char* )"start_task", //任务名称 (2)
(uint16_t )START_STK_SIZE, //任务堆栈大小 (3)
(void* )NULL, //传递给任务函数的参数 (4)
(UBaseType_t )START_TASK_PRIO, //任务优先级 (5)
(TaskHandle_t* )&StartTask_Handler); //任务句柄 (6

代码(1):任务入口函数,即任务函数的名称,需要我们自己定义并且实现。 代码(2):任务名字,字符串形式,最大长度由 FreeRTOSConfig.h 中定义 的 configMAX_TASK_NAME_LEN 宏指定,多余部分会被自动截掉,这里任务名字 最好要与任务函数入口名字一致,方便进行调试。 代码(3):任务堆栈大小,单位为字,在 32 位的处理器下(STM32),一个 字等于 4 个字节,那么任务大小就为 128 * 4 字节。 代码(4):任务入口函数形参,不用的时候配置为 0 或者 NULL 即可。 代码(5):任务的优先级。优先级范围根据 FreeRTOSConfig.h 中的宏 configMAX_PRIORITIES 决定,如果使能 configUSE_PORT_OPTIMISED_TASK_SELECTION,这个宏定义,则最多支持 32 个 优先级;如果不用特殊方法查找下一个运行的任务,那么则不强制要求限制最大 可用优先级数目。在 FreeRTOS 中,数值越大优先级越高,0 代表最低优先级。 代码(6):任务控制块指针,在使用内存的时候,需要给任务初始化函数 xTaskCreateStatic()传递预先定义好的任务控制块的指针。在使用动态内存的 时候,任务创建函数 xTaskCreate()会返回一个指针指向任务控制块,该任务控 制块是 xTaskCreate()函数里面动态分配的一块内存

整体代码

#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "usart.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 LED1_TASK_PRIO        2
//任务堆栈大小    
#define LED1_STK_SIZE         50  
//任务句柄
TaskHandle_t LED1Task_Handler;
//任务函数
void led1_task(void *pvParameters);

//任务优先级
#define LED2_TASK_PRIO        3
//任务堆栈大小    
#define LED2_STK_SIZE         50  
//任务句柄
TaskHandle_t LED2Task_Handler;
//任务函数
void led2_task(void *pvParameters);


/*******************************************************************************
* 函 数 名         : main
* 函数功能           : 主函数
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
int main()
{
    SysTick_Init(72);
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
    LED_Init();
    USART1_Init(115200);
    
    //创建开始任务
    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();           //进入临界区
      
    //创建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); 
                
    //创建LED2任务
    xTaskCreate((TaskFunction_t )led2_task,     
                (const char*    )"led2_task",   
                (uint16_t       )LED2_STK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )LED2_TASK_PRIO,
                (TaskHandle_t*  )&LED2Task_Handler); 
                
    vTaskDelete(StartTask_Handler); //删除开始任务
    taskEXIT_CRITICAL();            //退出临界区
} 

//LED1任务函数
void led1_task(void *pvParameters)
{
    while(1)
    {
        LED1=0;
        vTaskDelay(200);
        LED1=1;
        vTaskDelay(800);
    }
}

//LED2任务函数
void led2_task(void *pvParameters)
{
    while(1)
    {
        LED2=0;
        vTaskDelay(800);
        LED2=1;
        vTaskDelay(200);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值