RT-Thread 是一款具有显著优势的开源嵌入式实时操作系统。它不仅具备轻量级、实时性强的特点,还拥有广泛的开源社区支持和丰富的应用场景。
在轻量级方面,RT-Thread 能够适应资源受限的嵌入式环境,通过高效的内核设计和资源管理,为设备节省宝贵的系统资源。其小巧的内核可以在极小的存储空间中运行,为小型设备提供了可靠的操作系统选择。
实
时性是 RT-Thread 的核心优势之一。它具备快速的任务响应能力和精确的时间控制,能够满足对时间敏感的应用需求,如工业控制、航空航天等领域。
RT-Thread 的开源特性促进了其快速发展和广泛应用。众多开发者能够参与到其代码贡献和改进中,不断丰富其功能和优化性能。
在嵌入式系统领域,RT-Thread 得到了广泛的应用。从智能家居中的智能家电控
制,到工业自动化中的生产流程监控,再到汽车电子中的车载系统,都能看到它的身影。其强大的功能和良好的适应性,使得各类嵌入式设备能够稳定、高效地运行。
总之,RT-Thread 以其开源、轻量级和实时性等特点,在嵌入式系统领域发挥着重要作用,为开发者提供了可靠、高效的操作系统解决方案。
系统上电后,首先从启动文件开始运行。启动文件通常会完成一些基础的硬件设置,如初始化时钟、配置中断向量表以及初始化堆栈等。
接着,程序跳转至 RT-Thread 的入口函数 rtthread_startup 。在这个函数中,一系列重要的初始化工作依次展开。
首先是硬件初始化,包括设置系统时钟、初始化相关外设等,为后续的系统运行提供硬件
基础。
然后是系统内核对象的创建,如定时器、调度器等。这些内核对象的创建为系统的任务调度和时间管理提供了支持。
接下来创建 main 线程,同时会对线程栈进行初始化。main 线程通常承担着用户应用程序的主要逻辑。
在 rtthread_startup 函数中,还会进行定时器和调度器的初始化。定时器初始化确保
系统能够进行精确的定时操作,调度器初始化则为任务的合理分配和切换奠定基础。
在完成这些初始化工作后,系统准备就绪,等待调度器启动,从而开启系统的正常运行和任务调度。
总的来说,RT-Thread 的启动流程严谨有序,通过逐步完成各项初始化工作,为系统的稳定运行和高效任务处理提供了有力保障。
-
Code(代码段):
Code 段存放程序的代码部分。
在编译时确定其大小,运行时其内容不发生改变。
在程序编译时,代码段占用一定的 Flash 空间,运行时 CPU 从 Flash 中读取执行代码。
-
RO-data(只读数据段):
RO
-data 段用于存放程序中定义的常量,如字符串常量等。这些数据在编译时确定,且在运行时不可更改,位于 Flash 中。RO-data 段在编译时占用 Flash 空间。
-
RW-data(读写数据段):
RW-data 段存放初始化为非 0 值的全局变量。
在编译时,其占用一定的 Flash 空间;
在运行时,由于其中的数据需要读写操作,所以 RW-data 中的数据会被从 Flash 搬运到 RAM 中。
-
ZI-data(0 数据段):
ZI-data 段存放未初始化或初始化为 0 的全局变量。
ZI-data 段在编译时不占用 Flash 空间,在运行时根据编译器给出的 ZI 地址和大小在 RAM 中分配空间,并将其清零。
总的来说,在编译时,RO Size 包括 Code 及 RO-data,表示程序占用 Flash 空间的大小;RW Size 包括 RW-data 及 ZI-data,表示运行时占用的 RAM 大小;ROM Size 包括 Code、RO Data 以及 RW Data,表示烧写程序所占用的 Flash 空间大小。程序运行时,CPU 从 Flash 读取 Code 段和 RO-data 段的内容,从 RAM 读写 RW-data 段和 ZI-data 段的数据。
RT-Thread 的自动初始化机制通过巧妙的宏定义方式实现。在函数定义处使用特定的宏声明初始化函数,这些函数会在系统启动过程中自动被执行,无需手动调用。
INIT_BOARD_EXPORT 主要用于非常早期的初始化,例如芯片相关硬件的初始化,此时调度器还未启动。它适用于那些在系统启动极早期就必须完成的关键硬件初始化操作。
INIT_PREV_EXPORT 用于纯软件的初始化,通常是没有太多依赖的函数。比如一些简单的软件配置或早期的软件模块初始化。
INIT_DEVICE_EXPORT 针对外设驱动的初始化,如网卡设备等。在需要对外设进行初始化以便后续系统
正常使用时使用。
INIT_COMPONENT_EXPORT 主要用于组件的初始化,像文件系统或者 LWIP 等组件的初始化就可通过此宏。
INIT_ENV_EXPORT 用于系统环境的初始化,比如挂载文件系统等操作。
INIT_APP_EXPORT 则用于应用的初始化,比如 GUI 应用等。
通过这些不同类型的自动初始化接口,开发者能够根据具体的初始化需求,将函数放置在合适的初始化阶段,确保系统在启动过程中有序、高效地完成各项初始化工作,提高了开发效率和系统的稳定性。
RT-Thread 的内核对象丰富多样,包括线程、信号量、邮箱、消息队列、内存池等。
-
线程:
是 RT-Thread 中最基本的调度单位,描述了任务执行的上下文关系和优先等级。线程控制块存储了线程的关键信息,如优先级、状态、栈地址等。
-
信号量:
用于解决线程间的同步和互斥问题。通过信号量的计数值来控制资源的访问,当计数值为 0 时,申请资源的线程会被阻塞。
-
邮箱:
实现线程间的消息传递,能够存储一定量的消息数据。
-
消息队列:
可以存储多个消息,支持不同线程之间的异步通信。
-
内存池:
用于高效地管理内存分配和释放,提高内存使用效率。
内核对象管理框架通过链表来管理各类对象。每个内核对象类型都有对应的链表,对象通过链表节点进行连接。例如,线程对象通过线程链表进行管理。
对象的派生和继承关系带来了显著的优势。一方面,提高了系统的可重用性和扩展性。新的对象类别可以在继承通用属性的基础上进行少量扩展即可创建,降低了开发难度。另一方面,提供了统一的对象操作方式,简化了具体对象的操作流程,提高了系统的可靠性和稳定性。例如,线程控制块在继承通用对象结构的基础上,增加了线程特有的属性,使得线程管理更加精准和高效。
1、多线程的基本概念与 RT-Thread 中的实现
在操作系统中,多线程是将一个大型任务分解为多个可独立执行的小任务,从而提高系统的并发处理能力。在 RT-Thread 中,通过线程控制块来管理线程,每个线程都有自己的执行环境和优先级。线程之间可以通过共享资源和通信机制进行协作。
2、线程的相关属性
-
线程栈:
RT-Thread 中线程具有独立的栈,用于存储线程运行时的局部变量和上下文信息。
线程切换时,上下文会保存到栈中,恢复运行时再从栈中读取。
-
线程状态:
线
程存在初始、就绪、运行、挂起和关闭这五种状态。
初始状态表示线程刚创建未运行;
就绪状态意味着线程准备好等待被调度执行;
运行状态表示线程正在占用 CPU 执行;
挂起状态通常是由于资源不可用或主动延时导致线程暂时不参
与调度;
关闭状态则表示线程已结束。
-
线程优先级:
RT-Thread 支持最多 256 个优先级,数值越小优先级越高,0 为最高优先级。可根
据实际需求为不同线程设置优先级,以决定线程被调度的先后顺序。
-
时间片:
时间片仅对相同优先级的就绪态线程有效。
它决定了同一优先级线程每次被调度执行的时长,影响系统的响应性和任务切换频率。
3、系统线程
-
空闲线程
:
空闲线程是系统中优先级最低的线程,其状态永远为就绪态。当系统中无其他就绪线程
时,调度器会调度空闲线程。它通常是一个死循环,用于执行一些后台任务,如资源回收、功耗管理等。
-
主线程:
在系统启动时创建,入口函数为 main_thread_entry 。
用户的应用入口函数 main 从这里开始,用户可在 main 函数中添加应用程序的初始化代码。
4、线程调度的相关API