0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

FreeRTOS介绍与基础任务创建

码农爱学习 来源:码农爱学习 作者:码农爱学习 2022-09-26 09:00 次阅读

FreeRTOS简介

FreeRTOS,全称Free Real Time Operating System,即免费的实时操作系统。相比于计算机中用到的Windows,MacOS,Linux等操作系统,实时操作系统(RTOS)是一种轻量级的操作系统,适用于嵌入式硬件中,用于解决单片机类裸机轮询方式在处理多个任务时的实时性不高的问题。

目前的实时操作系统有好多种,除FreeRTOS外,还有μCOS、RT-Thread、RTX、Alios Things、Huawei LiteOS等。

什么是RTOS?

实时操作系统(RTOS)的主要特点是可以实现多任务,与多任务系统相对的是裸机系统。

裸机系统

裸机系统就是最初我们学习单片机编程时接触的那种编程方式,main函数中一个while大循环依次处理各个模块的任务,对于需要及时检测的事件会使用中断。这种使用大循环的程序运行方式也叫轮询系统,加上中断处理函数后又称前后台系统,中断处理称作前台,无限循环称作后台。

多任务系统

多任务系统是将各个处理模块编写为单独的任务,每个任务本身是个无限循环,程序运行初期会创建各个子任务,通过任务调度的方式,利用各任务的阻塞时刻不断切换运行各个任务,达到一种看起来是多个任务在同时运行的一种效果。并且,通过中断标志以及任务间通信的相关机制,可以实现任务之间的快速响应。

FreeRTOS特点

使用免费!

系统简单小巧、文件数量少、通常情况下内核占用4~9k字节空间

抢占式内核

代码主要由C编写,可移植性高,已实现在30多种架构的芯片上移植

任务与任务,任务与中断间的通信方式包括:信号量、消息队列、事件标志组、任务通知

具有优先级继承特性的互斥信号令,避免优先级反转问题

高效的软件定时器

FreeRTOS源码目录结构

这里以FreeRTOS v9.0.0版本为例,代码包含FreeRTOS和FreeRTOS-Plus文件夹,后者是一些补充文件,初学者用不到,可以先忽略。在FreeRTOS文件夹中主要关注source文件夹,这里是FreeRTOS的全部源码,包括6个c文件和include文件夹下的多个h文件。另外,在portable文件夹下,是针对不同硬件平台的单独区分使用的代码,目前考虑使用Keil开发STM32F407,所以portable文件夹只需使用RVDS的ARM_CM4F以及MemMang。

关于各个c文件的主要用途:

port.c : 针对不同硬件平台的接口

heap_4.c : 内存管理相关

croutine.c : 协程相关

event_groups.c : 事件标志组相关

list.c : 列表,FreeRTOS的一种基础数据结构

queue.c : 队列相关

tasks.c : 任务创建、挂起、恢复、调度相关

timers.c : 软件定时器相关

另外在Demo文件夹下还需要用到一个FreeRTOSConfig.h,该文件中通过各种宏定义的方式来配置FreeRTOS需要使用哪些资源。

poYBAGMwYBWASii5AAHkTVYjmyU506.png

任务相关API函数

任务创建 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(),这里先不介绍。

任务删除 vTaskDelete()

函数原型(tasks.c中):

void vTaskDelete( TaskHandle_t xTaskToDelete )

参数:

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

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

任务调度 vTaskStartScheduler()

函数原型(tasks.c中):

void vTaskStartScheduler( void )

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

程序设计

主函数

主函数还是我们熟悉的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();          
}

开始任务函数

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

//开始任务任务函数
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();            //退出临界区
}

两个任务函数

每个任务函数都是一个死循环,注意循环中必须添加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
	}
}

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
	}
}

运行结果

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

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

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • FreeRTOS
    +关注

    关注

    12

    文章

    473

    浏览量

    61357
  • 实时操作系统

    关注

    1

    文章

    185

    浏览量

    30528
收藏 人收藏

    评论

    相关推荐

    转:freeRTOS任务创建

    我们曾经在公众号里给大家推送过关于freeRTOS在NXP kinetis KV4x上的移植,得到了猿友大量的反馈,很多猿友还是感觉对基础的一些东西不懂,今天我们就从基础的任务创建讲起,任务
    发表于 07-14 14:18

    STM32CUBE的freertos任务创建

    目录问题说明解决步骤验证方案总结问题说明STM32CUBE的freertos任务创建十分简单方便,但却有一个麻烦:需要我们把要跑的任务具体代码都写进
    发表于 08-24 08:26

    FreeRTOS任务创建过程

    FreeRTOS笔记(四):任务创建/删除,挂起/解挂详解在第二篇笔记中介绍任务创建的API,
    发表于 02-08 06:10

    FreeRTOS创建任务的流程分享

    从零入门 FreeRTOS 操作系统之创建任务启动方式在 main() 函数中将硬件和 RTOS 系统先初始化好,然后创建一个启动任务后就启
    发表于 02-11 06:59

    FreeRTOS任务的使用

    FreeRTOS学习笔记(二):任务创建/删除,挂起/解挂上篇文章介绍任务相关的基础知识,本篇文章对F
    发表于 02-18 07:14

    FreeRTOS任务创建到闪存LED的基本应用程序

    应用程序 : 本代码是 FreeRTOS 任务的基本应用程序, 用于创建闪存 LED 任务 。 BSP 版本: M480系列 BSP CMSIS V3.04.000 硬件
    发表于 08-22 06:28

    FreeRTOS任务如何创建和删除?

    FreeRTOS移植到Cortex-M3硬件平台的文章中,我们已经见过任务创建API,但那篇文章的重点在于如何移植FreeRTOS,本文将重点放在
    的头像 发表于 03-11 18:08 2673次阅读

    FreeRTOS笔记(四):任务创建/删除,挂起/解挂详解

    FreeRTOS笔记(四):任务创建/删除,挂起/解挂详解在第二篇笔记中介绍任务创建的API,
    发表于 12-04 19:36 15次下载
    <b class='flag-5'>FreeRTOS</b>笔记(四):<b class='flag-5'>任务</b><b class='flag-5'>创建</b>/删除,挂起/解挂详解

    从零入门 FreeRTOS 操作系统之创建任务流程

    从零入门 FreeRTOS 操作系统之创建任务启动方式在 main() 函数中将硬件和 RTOS 系统先初始化好,然后创建一个启动任务后就启
    发表于 12-07 18:36 7次下载
    从零入门 <b class='flag-5'>FreeRTOS</b> 操作系统之<b class='flag-5'>创建</b><b class='flag-5'>任务</b>流程

    #FreeRTOS学习笔记(二):任务创建/删除,挂起/解挂

    FreeRTOS学习笔记(二):任务创建/删除,挂起/解挂上篇文章介绍任务相关的基础知识,本篇文章对F
    发表于 12-23 19:56 2次下载
    #<b class='flag-5'>FreeRTOS</b>学习笔记(二):<b class='flag-5'>任务</b><b class='flag-5'>创建</b>/删除,挂起/解挂

    FreeRTOS高级篇2---FreeRTOS任务创建分析

    FreeRTOS基础系列《FreeRTOS系列第10篇---FreeRTOS任务创建和删除》中介绍
    发表于 01-26 17:42 23次下载
    <b class='flag-5'>FreeRTOS</b>高级篇2---<b class='flag-5'>FreeRTOS</b><b class='flag-5'>任务</b><b class='flag-5'>创建</b>分析

    FreeRTOS系列第10篇---FreeRTOS任务创建和删除

    FreeRTOS移植到Cortex-M3硬件平台的文章中,我们已经见过任务创建API,但那篇文章的重点在于如何移植FreeRTOS,本文将重点放在
    发表于 01-26 17:56 13次下载
    <b class='flag-5'>FreeRTOS</b>系列第10篇---<b class='flag-5'>FreeRTOS</b><b class='flag-5'>任务</b><b class='flag-5'>创建</b>和删除

    FreeRTOS任务创建与删除

    FreeRTOS 中,每个执行线程都被称为”任务”。在嵌入式社区中,对此并没有一个公允的术语,但我更喜欢用”任务”而不是”线程”,因为从以前的经验来看,线程具有更多的特定含义。
    的头像 发表于 02-10 14:43 937次阅读

    RA FreeRTOS任务创建

    ,开发环境e 2 studio完美支持FreeRTOS,无需额外手动移植。以下介绍如何用瑞萨e 2 studio创建RA系列MCU的FreeRTOS工程。 对于不熟悉瑞萨的FSP开发环
    的头像 发表于 03-10 14:35 934次阅读

    RA FreeRTOS任务创建

    ,开发环境e2 studio完美支持FreeRTOS,无需额外手动移植。以下介绍如何用瑞萨e2 studio创建RA系列MCU的FreeRTOS工程。
    的头像 发表于 07-12 10:00 212次阅读
    RA <b class='flag-5'>FreeRTOS</b><b class='flag-5'>任务</b><b class='flag-5'>创建</b>