FreeRTOS入门教程(堆和栈)

简介: FreeRTOS入门教程(堆和栈)

前言

本篇文章正式学习FreeRTOS操作系统,我打算编写一系列文章带大家轻松快速入门FreeRTOS操作系统。


一、FreeRTOS操作系统介绍

FreeRTOS是一款开源、实时、嵌入式的操作系统,它被广泛应用于小型嵌入式系统和微控制器中。FreeRTOS的设计目标是提供一个轻量级、可移植、易于使用的实时操作系统,以协调和管理多个任务。FreeRTOS通过引入任务、信号量、消息队列、定时器等概念,使得应用程序可以按照预期的方式运行,从而实现了便捷的应用程序开发。

FreeRTOS的核心是一个调度器,它可以轮流调度多个任务,并确保它们在适当的时间运行。任务可以是周期性的、一次性的或者是某些事件驱动的。 FreeRTOS支持多种架构,包括x86、ARM、AVR等,因此可以适应不同的硬件平台和开发环境。此外,FreeRTOS还提供了丰富的API和示例代码,大大简化了开发人员在嵌入式系统中的开发工作。

FreeRTOS具有以下特点:

省内存:FreeRTOS的内核很小,最小系统只需要几千个字节的RAM空间。任务栈的大小可以动态创建,因此不会浪费内存。

可移植性:FreeRTOS可以在不同的平台上运行,无需修改代码。

实时性:FreeRTOS提供了实时调度器,任务的执行可以及时响应外部事件。

可靠性:FreeRTOS提供了对任务的优先级控制、定时器和错误处理功能,让应用程序更加稳定。

易用性:FreeRTOS提供了丰富的API和示例代码,让开发人员可以快速上手进行开发。

在使用FreeRTOS时,开发人员需要首先了解和熟悉FreeRTOS的基本概念和API。例如,需要了解任务的创建、删除、挂起、恢复等操作以及信号量、消息队列、定时器等实时操作系统的特性。在具体的应用程序开发中,开发人员可以通过组合和配置这些基本概念来实现具体的应用功能。

总之,FreeRTOS是一款可靠、可移植、省内存、易用的实时嵌入式操作系统,是小型嵌入式系统和微控制器开发的有力工具。


二、堆

1.概念介绍

堆(Heap)是计算机中的一种动态内存分配方法,是一块自由存储区域,可按需求动态分配和释放内存。堆的特点是应用程序可以根据需要在堆上分配内存大小和释放内存,而不会预留和浪费内存空间。堆的实现通常依赖于底层的操作系统或者运行时库。

堆的数据结构通常是由一个堆顶指针来表示堆的起始地址,堆中的内存被划分为多个块,每个块上都有一个头部来记录当前块的状态和大小等信息,并且块按照大小顺序排列。应用程序可以通过调用malloc和free函数来在堆上动态分配和释放内存。当在堆上分配内存时,malloc函数会在堆上找到一块足够的连续内存空间,并返回其首地址,而当释放内存时,free函数会将被释放的内存块标记为可用,并放回堆中由堆管理器维护。

2.简单实现

char heap_buf[1024];//定义一块空闲内存空间
int pos = 0;//指向分配好的空间的第一个位置
/*
size:要分配内存的大小
*/
void *my_malloc(int size)
{
  int old_pos = pos;
  pos += size;//移动位置
  return &heap_buf[old_pos];//返回分配好的内存空间
}

这里画一张图让大家更好的理解:

使用:

char *buf = my_malloc(100);
for (i = 0; i < 100; i++)
{
  buf[i] = i;
}

三、栈

在FreeRTOS中,栈起着非常重要的作用。每个任务都需要一个堆栈来存储其运行时的上下文环境和局部变量。栈的大小和分配方式都会影响到任务的执行效率和系统稳定性。

在FreeRTOS中,任务的创建时需要指定任务的堆栈大小,在任务开始前系统会为任务分配指定大小的内存空间作为堆栈。

可见栈在FreeRTOS中还是非常重要的。

我们来举一个简单的例子看看栈具体的作用实现:

这个程序看起来是非常简单的,就是在main函数中调用funA在funA函数中调用funB和funC,但是里面却包含了栈的很多知识点。

这里先提几个问题后面我们进行讲解,当指向完函数funA后程序是怎么知道要跳转回到main函数中执行retrun 0的?

void funB(void)
{
}
void funC(void)
{
}
void funA(void)
{
  funB();
  funC();
}
int main(void)
{
  funA();
  retrun 0;
}

这里就需要先介绍一个非常重要的寄存器和函数栈的概念了:

LR寄存器介绍:

LR寄存器是ARM体系结构中的一种寄存器,全称为Link Register,用于存储返回地址。在ARM处理器中,函数调用时将返回地址存储在LR寄存器中。当函数返回时,处理器通过读取LR寄存器中的返回地址来跳转回调用函数的位置,从而实现函数返回和程序流转。

函数栈的介绍:

函数调用时使用的栈通常被称为函数栈。函数栈是一种数据结构,具有后进先出(LIFO)的特点,并且往往是在程序运行时通过内存分配来创建的。函数栈用于存储函数调用过程中的局部变量、函数参数、返回地址以及其他必要的堆栈帧数据。

每个函数在进入时需要在栈中创建一个堆栈帧,堆栈帧包含了函数所需的所有信息,如函数参数、局部变量、函数调用者的帧指针、返回地址等。随着函数的运行,堆栈中会不断地分配新的堆栈帧,并在函数返回时依次弹出这些帧以回收内存空间。

函数栈的常见使用场景包括:函数的参数和局部变量的存储、异常处理和调试等。

介绍完这些概念后我们就来分析上面的这个程序:

1.首先会调用到funA函数,当调用funA函数时相应的会创建出一个funA函数的栈,然后将retrun 0这段代码的返回地址保存到funA栈中的LR寄存器中。

2.进入funA函数后调用funB函数,对应的也会创建出一个funB函数的栈,然后将funC这段代码的返回地址保存到funB栈中的LR寄存器中。

3.同样的调用funC时也会创建出对应的栈用来保存返回地址。

4.当函数funB执行完成后会从栈中取出LR保存的返回地址去执行funC函数。

5.当函数funA执行完成后会从栈中取出LR保存的返回地址去执行retrun 0这条语句。

下面画一张图让大家更好的理解栈中存储的内容:

每一个函数都会有自己的栈空间,这些栈空间是互相独立的不会互相干扰。当执行完对应的函数后会从函数栈中将LR寄存器中保存的地址取出来去执行相对于的语句或者函数。


总结

栈在FreeRTOS中创建任务是非常重要的,每一个任务都有自己对应的栈,这些内容我们后面会讲解到。欢迎大家指点错误,也希望大家多点赞多支持,我将持续更新,后续程序源码将放在公众号中。


目录
打赏
0
0
0
0
14
分享
相关文章
|
3月前
|
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
55 1
|
1月前
|
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
144 77
☀☀☀☀☀☀☀有关栈和队列应用的oj题讲解☼☼☼☼☼☼☼
### 简介 本文介绍了三种数据结构的实现方法:用两个队列实现栈、用两个栈实现队列以及设计循环队列。具体思路如下: 1. **用两个队列实现栈**: - 插入元素时,选择非空队列进行插入。 - 移除栈顶元素时,将非空队列中的元素依次转移到另一个队列,直到只剩下一个元素,然后弹出该元素。 - 判空条件为两个队列均为空。 2. **用两个栈实现队列**: - 插入元素时,选择非空栈进行插入。 - 移除队首元素时,将非空栈中的元素依次转移到另一个栈,再将这些元素重新放回原栈以保持顺序。 - 判空条件为两个栈均为空。
|
1月前
|
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
【数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】初始化队列、销毁队列、判断队列是否为空、进队列、出队列等。本关任务:编写一个程序实现环形队列的基本运算。(6)出队列序列:yzopq2*(5)依次进队列元素:opq2*(6)出队列序列:bcdef。(2)依次进队列元素:abc。(5)依次进队列元素:def。(2)依次进队列元素:xyz。开始你的任务吧,祝你成功!(4)出队一个元素a。(4)出队一个元素x。
47 13
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
|
1月前
|
【C++数据结构——栈与队列】链栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现链栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储整数,最大
46 9
|
1月前
|
C++
【C++数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】
【数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】(1)遇到左括号:进栈Push()(2)遇到右括号:若栈顶元素为左括号,则出栈Pop();否则返回false。(3)当遍历表达式结束,且栈为空时,则返回true,否则返回false。本关任务:编写一个程序利用栈判断左、右圆括号是否配对。为了完成本关任务,你需要掌握:栈对括号的处理。(1)遇到左括号:进栈Push()开始你的任务吧,祝你成功!测试输入:(()))
39 7
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
100 5
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。
116 21
执行上下文和执行栈
执行上下文是JavaScript运行代码时的环境,每个执行上下文都有自己的变量对象、作用域链和this值。执行栈用于管理函数调用,每当调用一个函数,就会在栈中添加一个新的执行上下文。
|
3月前
|
数据结构之购物车系统(链表和栈)
本文介绍了基于链表和栈的购物车系统的设计与实现。该系统通过命令行界面提供商品管理、购物车查看、结算等功能,支持用户便捷地管理购物清单。核心代码定义了商品、购物车商品节点和购物车的数据结构,并实现了添加、删除商品、查看购物车内容及结算等操作。算法分析显示,系统在处理小规模购物车时表现良好,但在大规模购物车操作下可能存在性能瓶颈。
74 0

热门文章

最新文章