搜索
ST MCU Finder
安装免费手机应用,
寻找理想的ST MCU

[应用相关] RT-Thread读书笔记+内核篇

[复制链接]
290|4
 楼主 | 2019-6-12 16:26 | 显示全部楼层 | 奖励家园币|阅读模式
本帖最后由 sylar^z 于 2019-6-12 16:26 编辑

读书笔记-0-1学习RT-Thread内核(4-12章)


      这部分以RT-Thread Nano 为蓝本,对内核中的线程、线程切换、线程优先级、线程时间片及线程切换保护相关功能实现做了详细的说明,教大家怎么从 0 开始 RT-thread 写出来。在源码实现的过程中,涉及到的数据类型,变量名称,函数名称,文件名称以及文件的存放目录都会完全按照 RT-Thread 的来实现。当你学完这本书之后可以无缝地切换到原版的 RT-Thread 的使用。
      书中例程使用KEIL5v5.23版本编写和调试,实际使用时只要为5.xx版本皆可。在创建工程前先按RT-Thread源码的目录结构建立文件夹。书中对KEIL5下创建工程过程有详细介绍。

      过程包括了选择目标处理器(ARMCM3 / ARMCM4 / ARMCM7:
       2-1.jpg


      CMSIS中点选COREDEVICEStartup文件:
       2-2.jpg


       2-3.jpg


      创建工程文件组:
       2-5.jpg        2-4.jpg

      添加工程文件:
       2-7.jpg        2-6.jpg

设置调试模式:
       2-8.jpg


      设置时钟大小:
       2-9.jpg


      添加头文件路径:
       2-10.jpg


      至此,工程建立完毕。这个流程也适合于其他工程的建立。


关于系统—— 裸机系统和多线程系统
       裸机系统通常分为查询系统和前后台系统。
      查询系统即程序在初始化硬件后,通过一个无限循环来有序循环执行各功能。查询系统只能按设计的顺序执行,且受每个功能执行时间的限制,无法响应外部驱动事件。如果需要对外部驱动事件(按键事件等)做出响应,则要使用前后台系统。
      相比轮询系统,前后台系统是在轮询系统的基础上加入了中断。当有外部驱动事件,比如按键事件产生时,系统在前台(中断)中设置对应标志或直接执行简短事件的操作。当后台(main函数中的无限循环)执行到按键事件处理时,根据前台设置的标志来确定是否有事件产生,进而执行对应操作。这样系统可以避免事件被遗漏,但还无法避免事件响应被延后执行。
      多线程系统则将不同的功能安排在不同的线程中,当一个或多个事件产生在中断中被捕获后,通过对个线程的优先级判断,来优先执行重要事件。相比前后台系统,多线程系统的实时性提高了。
      有关这三者的软件模型区别:

       2-11.jpg


关于链表
      链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。简单的说,链表就是一条循环的数据链,数据链上的每一个节点即一个单元数据。通过一个指向前一个节点的指针和一个指向后一个节点的指针来实现节点的串联。
                   链表节点数据类型最简单的结构如下:

2-12.jpg


      由 rt_list_t 类型的节点构成的双向链表示意图如下。
      单个节点,即节点的前一个节点与后一个节点都是本身:

       2-14.jpg

      多个节点:
       2-13.jpg

      添加一个节点。插入在表头前与表头后类似,这里以插入表头后为例。步骤:
      1.插入点后一个节点的prev指针指向新节点;
      2.新节点的next指针指向插入点后一个节点
      3.插入点前一个节点的next指针指向新节点
      4.新节点的prev指针指向插入点前一个节点
      通过以上四个步骤就完成了一个新节点的插入。
       2-15.jpg

      删除一个节点。步骤:
      1.删除节点后一个节点的prev指针指向删除节点前一个节点;
      2.删除节点前一个节点的next指针指向删除节点后一个节点
      3.删除节点的prev指针和next指针都指向删除节点本身
      通过以上三个步骤就完成了一个节点的删除。
       2-16.jpg


      链表在系统的应用中比较广泛,无论是线程、信号量、消息队列、数据等各种类型的对象都会使用到链表功能。


      多线程系统至少包含线程栈、线程就绪列表、线程调度器三大部分。
      线程栈用于线程切换时对当前线程的寄存器值和数据进行保存。在线程恢复时从栈例调回寄存器和数据,以保证线程恢复时和切换前的状态一致。
      线程就绪列表中排列的是等待执行的线程。每个线程在完成预备事件(延时等待、外部驱动触发的)后被放入线程就绪列表中。线程就绪列表根据线程优先级级数由多个列表组成列表数组。准备就绪的线程被插入到对应优先级的列表中等待执行。
      线程调度器是操作系统的核心,其主要功能就是实现线程的切换。线程调度器从就绪列表里面检索出下一个就绪的优先级最高的线程并执行,同时将执行完毕的线程移出就绪列表(延时等待等情况下)或则插入到就绪列表的最后节点处(时间片模式等情况)。在同一个优先级由多个线程时,可以增加线程定时器来,通过每个线程定时器来确认当前线程执行的时间,这被称为线程时间片功能。这样多个通优先级的线程可以分时执行,提高系统的实时性。
      那线程调度器在何时执行呢?时间片功能如何实现呢?当所有线程都处于预备状态时,系统又在做什么呢?
      首先当一个线程执行完毕后,调用系统调度器进行线程切换;当一个线程执行到等待延时(阻塞延时,线程调用该延时函数后,线程会被剥离 CPU 使用权)时,也将调用系统调度器进行线程切换。在时间片模式下,当线程的执行时间到了,也将调用系统调度器进行线程切换。
       线程时间片功能实现需要一个周期性的中断来记录当前线程的运行时间。在 RT-Thread 中,这个周期由 SysTick 中断提供,操作系统里面的最小的时间单位就是 SysTick 的中断周期。中断周期可以通过SysTick_Config()函数配置,这里配置为10ms。线程的执行时间在SysTick 中断中记录,在执行时间到后,调用系统调度器。线程的阻塞延时也是通过这个方式进行记录处理。
      当所有线程都处于预备时,线程就绪链表就是空的。线程调度器就无法找到可执行线程,如果系统一直在线程调度器中检索线程无疑是对性能的浪费。所以RTOS都会创建一个空闲线程。在RT-Thread中,空闲线程是系统在初始化的时候创建的优先级最低的线程,空闲线程主体主要是做一些系统内存的清理工作。

使用特权

评论回复
| 2019-6-13 00:46 | 显示全部楼层 | 奖励家园币
LZ的配图很有条理,很用心。
虽然现在还没搞RTOS,但必须要回帖支持一下!

使用特权

评论回复

评论

sylar^z 2019-6-13 08:38 回复TA
谢谢支持 
| 2019-7-5 09:41 | 显示全部楼层 | 奖励家园币
都读的这么深入了啊

使用特权

评论回复
| 2019-7-5 09:46 | 显示全部楼层 | 奖励家园币
我卡在第一章的代码上了

使用特权

评论回复
扫描二维码,随时随地手机跟帖
您需要登录后才可以回帖 登录 | 注册

本版积分规则

我要发帖 投诉建议 创建版块 申请版主

快速回复

您需要登录后才可以回帖
登录 | 注册
高级模式

论坛热帖

在线客服 快速回复 返回顶部 返回列表