由浅入深学习FreeRTOS-系列文章目录
第一章 汇编指令以及堆栈概念
第二章 RTOS如何使用栈
文章目录
前言
在第一章 汇编指令以及堆栈概念中,有提到多线程编程的基础是栈,每个RTOS线程都有自己的栈。
一、FreeRTOS是什么?
FreeRTOS操作系统是完全免费的操作系统,具有源码公开、可移植、可裁减、调度策略灵活的特点,可以方便地移植到各种单片机上运行。
作为一个轻量级的操作系统,FreeRTOS提供的功能包括:任务管理、时间管理、信号量、消息队列、内存管理、记录功能等,可基本满足较小系统的需要。
FreeRTOS内核支持优先级调度算法,每个任务可根据重要程度的不同被赋予一定的优先级,CPU总是让处于就绪态的、优先级最高的任务先运行。
FreeRT0S内核同时支持轮换调度算法,系统允许不同的任务使用相同的优先级,在没有更高优先级任务就绪的情况下,同一优先级的任务共享CPU的使用时间。
二、为什么每个线程都有自己的栈?
在实时操作系统(RTOS)中,每个线程(或任务)通常都有自己的栈空间,用于存储该线程的局部变量、函数调用返回地址、寄存器保存等信息。这有助于实现线程的独立性和安全性,使得一个线程的错误不会影响到其他线程。
1.FreeRTOS中的线程栈
FreeRTOS 是一个广泛使用的开源实时操作系统。我们将通过一个具体的例子,展示如何在 FreeRTOS 中为每个线程分配栈空间。
1)配置 FreeRTOS 堆和栈大小
首先,在 FreeRTOS 配置文件 FreeRTOSConfig.h 中定义每个任务的栈大小和堆的大小:
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 10 * 1024 ) ) // 10KB 堆内存
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 128 ) // 最小栈大小为128个字
2)创建任务
在 FreeRTOS 中,每个任务都有自己的任务函数和栈空间。可以通过 xTaskCreate 函数来创建任务,并为其分配栈空间。
#include "FreeRTOS.h"
#include "task.h"
// 任务句柄
TaskHandle_t Task1Handle = NULL;
TaskHandle_t Task2Handle = NULL;
// 任务函数
void Task1(void *pvParameters) {
for(;;) {
// 任务代码
// ...
}
}
void Task2(void *pvParameters) {
for(;;) {
// 任务代码
// ...
}
}
int main(void) {
// 创建任务1,栈大小为200个字,每个任务函数都会在一个无限循环中运行其任务代码
xTaskCreate(Task1, "Task1", 200, NULL, 1, &Task1Handle);
// 创建任务2,栈大小为300个字,每个任务函数都会在一个无限循环中运行其任务代码
xTaskCreate(Task2, "Task2", 300, NULL, 1, &Task2Handle);
// 启动 FreeRTOS 调度器,开始运行任务
vTaskStartScheduler();
// 代码不应到达此处
for(;;);
}
3) FreeRTOS 任务切换
FreeRTOS 调度器会根据设定的任务优先级和调度策略,自动进行任务切换。在每次任务切换时,RTOS 会保存当前任务的上下文(包括寄存器、程序计数器、栈指针等),然后恢复下一个任务的上下文。这保证了每个任务的栈和局部变量是独立的。
4) 任务栈的分配和使用
FreeRTOS 在任务创建时,自动为每个任务分配栈空间,并在任务切换时管理这些栈。以下是栈分配的示意图:
每个任务都有自己的栈空间,堆内存用于动态分配。
任务1的栈空间大小为200个字,任务2的栈空间大小为300个字。
堆用于存储动态分配的内存,如队列、信号量等。
编译并运行上述代码后,FreeRTOS 调度器会启动并运行两个任务。每个任务在其独立的栈空间中运行,不会干扰其他任务的栈。
总结
以上