FreeRTOS内核实现与应用开发实战指南:基于STM32》(FreeRTOS内核实现与应用开发实战指南:基于STM32)

网友投稿 1933 2022-05-30

电子与嵌入式系统设计丛书

FreeRTOS内核实现与应用开发实战指南:

基于STM32

刘火良 杨 森 编著

前  言

如何学习本书

本书系统讲解FreeRTOS,共分为两个部分。第一部分重点讲解FreeRTOS的原理实现,从0开始,不断迭代,教你把FreeRTOS的内核写出来,让你彻底学会任务是如何定义的、系统是如何调度的(包括底层的汇编代码讲解)、多优先级是如何实现的等操作系统最深层次的知识。当你拿到本书开始学习的时候,你一定会惊讶,原来RTOS(Real Time Operating System,实时操作系统)的学习并没有那么复杂,反而是那么有趣,原来自己也可以写RTOS,成就感瞬间爆棚。

当彻底掌握第一部分的知识之后,再学习其他RTOS,可以说十分轻松。纵观现在市面上流行的几种RTOS,它们的内核实现差异不大,只需要深入研究其中一种即可,没有必要对每一种RTOS都深入地研究源码。但如果时间允许,看一看也并无坏处。第二部分重点讲解FreeRTOS的移植、内核中每个组件的应用,比起第一部分,这部分内容掌握起来应该比较容易。

全书内容循序渐进,不断迭代,尤其在第一部分,前一章多是后一章的基础,建议从头开始阅读,不要进行跳跃式阅读。在学习时务必做到两点:一是不能一味地看书,要把代码和书本结合起来学习,一边看书,一边调试代码。如何调试代码呢?即单步执行每一条程序,看程序的执行流程和执行的效果与自己所想的是否一致。二是在每学完一章之后,必须将配套的例程重写一遍(切记不要复制,哪怕是一个分号。但可以照书录入),做到举一反三,确保真正理解。在自己写的时候肯定会错漏百出,要认真纠错,好好调试,这是你提高编程能力的最好机会。记住,编写程序不是一气呵成的,而是要一步一步地调试。

本书的编写风格

本书第一部分以FreeRTOS V9.0.0官方源码为蓝本,抽丝剥茧,不断迭代,教你如何从0开始把FreeRTOS内核写出来。书中涉及的数据类型、变量名称、函数名称、文件名称、文件存放的位置都完全按照FreeRTOS官方的方式来实现。学完这本书之后,你可以无缝地切换到原版的FreeRTOS中使用。要注意的是,在实现的过程中,某些函数中会去掉一些形参和冗余的代码,只保留核心的功能,但这并不会影响学习。

本书第二部分主要介绍FreeRTOS的移植和内核组件的使用,不会再去深入讲解源码,而是着重讲解如何应用,如果对第一部分不感兴趣,可以跳过第一部分,直接进入第二部分的学习。

本书还有姊妹篇—《RT-Thread内核实现与应用开发实战指南:基于STM32》,两本书的编写风格、内容框架和章节命名与排序基本一致,语言阐述类似,且涉及RTOS抽象层的理论部分也相同,不同之处在于RTOS的实现原理、内核源码的讲解和上层API的使用,这些内容才是重点部分,是读者学习的核心。例如,虽然两本书的第一部分的章节名称基本类似,但内容不同,因为针对的RTOS不一样。其中,关于新建FreeRTOS工程和裸机系统与多任务(线程)系统的描述属于RTOS抽象层的理论部分,不具体针对某个RTOS,所以基本一样。第二部分中,对于什么是任务(线程)、阻塞延时和信号量的应用等RTOS抽象层的理论讲解也基本类似,但是具体涉及这两个RTOS的原理实现和代码讲解时则完全不同。

如果读者已经学习了其中一本书,再学习另外一本的话,那么涉及RTOS抽象层的理论部分可跳过,只需要把精力放在RTOS内核的实现和源码API的应用方面。因为现有的RTOS在理论层基本都是相通的,但在具体的代码实现上各有特点,所以可以用这两本书进行互补学习,掌握了其中一本书的知识,再学习另外一本书定会得心应手,事半功倍。

本书的参考资料及配套硬件

关于本书的参考资料和配套硬件的信息,请参考本书附录部分。

本书的技术论坛

如果在学习过程中遇到问题,可以到野火电子论坛www.firebbs.cn发帖交流,开源共享,共同进步。

引  言

为什么要学习RTOS

当我们进入嵌入式这个领域时,首先接触的往往是单片机编程,单片机编程又首选51单片机来入门。这里面说的单片机编程通常都是指裸机编程,即不加入任何RTOS的编程。常用的RTOS有国外的FreeRTOS、μC/OS、RTX和国内的FreeRTOS、Huawei LiteOS和AliOS-Things等,其中,开源且免费的FreeRTOS的市场占有率最高。

在裸机系统中,所有的程序基本都是自己写的,所有的操作都是在一个无限的大循环中实现。现实生活中的很多中小型电子产品中用的都是裸机系统,而且能够满足需求。但是为什么还要学习RTOS编程,要涉及一个操作系统呢?一是因为项目需求,随着产品要实现的功能越来越多,单纯的裸机系统已经不能完美地解决问题,反而会使编程变得更加复杂,如果想降低编程的难度,可以考虑引入RTOS实现多任务管理,这是使用RTOS的最大优势;二是出于学习的需要,必须学习更高级的技术,实现更好的职业规划,为将来能有更好的职业发展做准备,而不是一味拘泥于裸机编程。作为一个合格的嵌入式软件工程师,学习是永远不能停歇的,时刻都得为将来做准备。书到用时方恨少,希望当机会来临时,你不要有这种感觉。

为了帮大家厘清RTOS编程的思路,本书会在第3章简单地分析这两种编程方式的区别,我们将这个区别称为“学习RTOS的命门”,只要掌握这一关键内容,以后的RTOS学习可以说是易如反掌。在讲解这两种编程方式的区别时,我们主要讲解方法论,不会涉及具体的代码,即主要还是通过伪代码来讲解。

如何学习RTOS

裸机编程和RTOS编程的风格有些不一样,而且有很多人说学习RTOS很难,这就导致想要学习的人一听到RTOS编程就在心里忌惮三分,结果就是“出师未捷身先死”。

那么到底如何学习RTOS呢?最简单的方法就是在别人移植好的系统上,先看看RTOS中API的使用说明,然后调用这些API实现自己想要的功能,完全不用关心底层的移植,这是最简单、快速的入门方法。这种方法有利有弊。如果是做产品,好处是可以快速地实现功能,将产品推向市场,赢得先机;弊端是当程序出现问题时,因对RTOS不够了解,会导致调试困难。如果想系统地学习RTOS,那么只会简单地调用API是不可取的,我们应该深入学习其中一款RTOS。

目前市场上的RTOS,其内核实现方式差异不大,我们只需要深入学习其中一款即可。万变不离其宗,只要掌握了一款RTOS,以后换到其他型号的RTOS,使用起来自然也是得心应手。那么如何深入地学习一款RTOS呢?这里有一个非常有效但也十分难的方法,就是阅读RTOS的源码,深入研究内核和每个组件的实现方式。这个过程枯燥且痛苦。但为了能够学到RTOS的精华,还是很值得一试的。

市面上虽然有一些讲解相关RTOS源码的图书,但如果基础知识掌握得不够,且先前没有使用过该款RTOS,那么只看源码还是会非常枯燥,并且不能从全局掌握整个RTOS的构成和实现。

现在,我们采用一种全新的方法来教大家学习一款RTOS,既不是单纯地介绍其中的API如何使用,也不是单纯地拿里面的源码一句句地讲解,而是从0开始,层层叠加,不断完善,教大家如何把一个RTOS从0到1写出来,让你在每一个阶段都能享受到成功的喜悦。在这个RTOS实现的过程中,只需要具备C语言基础即可,然后就是跟着本书笃定前行,最后定有所成。

选择什么RTOS

用来教学的RTOS,我们不会完全从头写一个,而是选取目前国内外市场占有率很高的FreeRTOS为蓝本,将其抽丝剥茧,从0到1写出来。在实现的过程中,数据类型、变量名、函数名称、文件类型等都完全按照FreeRTOS里面的写法,不会再重新命名。这样学完本书之后,就可以无缝地过渡到FreeRTOS了。

目  录

前 言

引 言

第一部分 从0到1教你写FreeRTOS内核

第1章 初识FreeRTOS  2

1.1 FreeRTOS版权  2

1.2 FreeRTOS收费问题  2

1.2.1 FreeRTOS  2

1.2.2 OpenRTOS  2

1.2.3 SaveRTOS  3

1.3 FreeRTOS资料获取  3

1.3.1 获取源码  3

1.3.2 获取书籍  4

1.3.3 快速入门  4

1.4 FreeRTOS的编程风格  5

1.4.1 数据类型  5

1.4.2 变量名  6

1.4.3 函数名  6

1.4.4 宏  7

1.4.5 格式  7

第2章 新建FreeRTOS工程—软件仿真  8

2.1 新建本地工程文件夹  8

2.2 使用KEIL新建工程  8

2.2.1 New Project  9

2.2.2 Select Device for Target  9

2.2.3 Manage Run-Time Environment  10

2.3 在KEIL工程中新建文件组  11

2.4 在KEIL工程中添加文件  11

2.5 调试配置  13

2.5.1 设置软件仿真  13

2.5.2 修改时钟大小  13

2.5.3 添加头文件路径  13

第3章 裸机系统与多任务系统  15

3.1 裸机系统  15

3.1.1 轮询系统  15

3.1.2 前后台系统  16

3.2 多任务系统  17

第4章 数据结构—列表与列表项  20

4.1 C语言链表  20

4.1.1 单向链表  20

4.1.2 双向链表  22

4.1.3 链表与数组的对比  22

4.2 FreeRTOS中链表的实现  23

4.2.1 实现链表节点  23

4.2.2 实现链表根节点  25

4.3 链表节点插入实验  31

4.4 实验现象  34

第5章 任务的定义与任务切换  35

5.1 本章目标  35

5.2 什么是任务  36

5.3 创建任务  37

5.3.1 定义任务栈  37

5.3.2 定义任务函数  38

5.3.3 定义任务控制块  39

5.3.4 实现任务创建函数  40

5.4 实现就绪列表  45

5.4.1 定义就绪列表  45

5.4.2 就绪列表初始化  45

5.4.3 将任务插入就绪列表  46

5.5 实现调度器  49

5.5.1 启动调度器  49

5.5.2 任务切换  54

5.6 main()函数  58

5.7 实验现象  61

5.8 本章涉及的汇编指令  64

第6章 临界段的保护  65

6.1 什么是临界段  65

6.2 Cortex-M内核快速关中断指令  65

6.3 关中断  66

6.3.1 不带返回值的关中断函数  66

6.3.2 带返回值的关中断函数  67

6.4 开中断  67

6.5 进入/退出临界段的宏  68

6.5.1 进入临界段  68

6.5.2 退出临界段  69

6.6 临界段代码的应用  70

6.7 实验现象  71

第7章 空闲任务与阻塞延时  72

7.1 实现空闲任务  72

7.1.1 定义空闲任务的栈  72

7.1.2 定义空闲任务的任务控制块  73

7.1.3 创建空闲任务  73

7.2 实现阻塞延时  74

7.2.1 vTaskDelay()函数  74

7.2.2 修改vTaskSwitchContext()函数  75

7.3 SysTick中断服务函数  77

7.4 SysTick初始化函数  78

7.5 main()函数  80

7.6 实验现象  83

第8章 多优先级  84

8.1 支持多优先级的方法  84

8.2 查找最高优先级的就绪任务相关代码  85

8.2.1 通用方法  87

8.2.2 优化方法  87

8.3 修改代码以支持多优先级  89

8.3.1 修改任务控制块  89

8.3.2 修改xTaskCreateStatic()函数  89

8.3.3 修改vTaskStartScheduler()函数  93

8.3.4 修改vTaskDelay()函数  94

8.3.5 修改vTaskSwitchContext()函数  95

8.3.6 修改xTaskIncrementTick()函数  96

8.4 main()函数  97

8.5 实验现象  100

第9章 任务延时列表  102

9.1 任务延时列表的工作原理  102

9.2 实现任务延时列表  103

9.2.1 定义任务延时列表  103

9.2.2 任务延时列表初始化  103

9.2.3 定义xNextTaskUnblock-Time  103

9.2.4 初始化xNextTaskUnblock-Time  104

9.3 修改代码以支持任务延时列表  104

9.3.1 修改vTaskDelay()函数  105

9.3.2 修改xTaskIncrementTick()函数  107

9.3.3 修改taskRESET_READY_PRIORITY()函数  109

9.4 main()函数  110

9.5 实验现象  110

第10章 时间片  111

10.1 时间片测试实验  111

10.2 main.c文件  112

10.3 实验现象  115

10.4 原理分析  116

10.4.1 taskSELECT_HIGHEST_PRIORITY_TASK()函数  116

10.4.2 taskRESET_READY_PRIORITY()函数  117

10.5 修改代码以支持优先级  118

10.5.1 修改xPortSysTick-Handler()函数  118

10.5.2 修改xTaskIncrement-Tick()函数  119

第二部分 FreeRTOS内核应用开发

第11章 移植FreeRTOS到STM32  124

11.1 获取STM32的裸机工程模板  124

11.2 下载FreeRTOS V9.0.0源码  124

11.3 FreeRTOS文件夹内容  126

11.3.1 FreeRTOS文件夹  126

11.3.2 FreeRTOS-Plus文件夹  128

11.3.3 HTML文件  129

11.4 向裸机工程中添加FreeRTOS源码  129

11.4.1 提取FreeRTOS最简源码  129

11.4.2 复制FreeRTOS到裸机工程根目录  130

11.4.3 复制FreeRTOSConf?ig.h文件到User文件夹  131

11.4.4 添加FreeRTOS源码到工程组文件夹  131

11.5 修改FreeRTOSConf?ig.h文件  133

11.5.1 FreeRTOSConf?ig.h文件内容  133

11.5.2 修改FreeRTOSConfig.h文件  143

11.6 修改stm32f10x_it.c文件  147

11.7 修改main.c文件  151

11.8 下载验证  152

第12章 任务  153

12.1 硬件初始化  153

12.2 创建单任务—SRAM静态内存  155

12.2.1 定义任务函数  155

12.2.2 空闲任务与定时器任务栈函数实现  155

12.2.3 定义任务栈  157

12.2.4 定义任务控制块  157

12.2.5 静态创建任务  158

12.2.6 启动任务  159

12.2.7 main.c文件  159

12.3 下载验证SRAM静态内存单任务  164

12.4 创建单任务—SRAM动态内存  164

12.4.1 动态内存空间堆的来源  164

12.4.2 定义任务函数  165

12.4.3 定义任务栈  166

12.4.4 定义任务控制块指针  166

12.4.5 动态创建任务  166

12.4.6 启动任务  167

12.4.7 main.c文件  167

12.5 下载验证SRAM动态内存单任务  171

12.6 创建多任务—SRAM动态内存  171

12.7 下载验证SRAM动态内存多任务  175

第13章 FreeRTOS的启动流程  176

13.1 “?万事俱备,只欠东风?”法  176

13.2 “?小心翼翼,十分谨慎?”法  177

13.3 两种方法的适用情况  179

13.4 FreeRTOS的启动流程  179

13.4.1 创建任务函数xTaskCreate()  179

13.4.2 开启调度器函数vTask-StartScheduler()  181

13.4.3 main()函数  185

第14章 任务管理  188

14.1 任务的基本概念  188

14.2 任务调度器的基本概念  188

14.3 任务状态的概念  189

14.4 任务状态迁移  190

14.5 常用的任务函数  191

14.5.1 任务挂起函数  191

14.5.2 任务恢复函数  195

14.5.3 任务删除函数  203

14.5.4 任务延时函数  207

14.6 任务的设计要点  215

14.7 任务管理实验  216

14.8 实验现象  221

第15章 消息队列  222

15.1 消息队列的基本概念  222

15.2 消息队列的运作机制  222

《FreeRTOS内核实现与应用开发实战指南:基于STM32》(FreeRTOS内核实现与应用开发实战指南:基于STM32)

15.3 消息队列的阻塞机制  223

15.4 消息队列的应用场景  224

15.5 消息队列控制块  224

15.6 常用的消息队列函数  226

15.6.1 消息队列动态创建函数  226

15.6.2 消息队列静态创建函数  232

15.6.3 消息队列删除函数  233

15.6.4 向消息队列发送消息函数  234

15.6.5 从消息队列读取消息函数  244

15.7 消息队列注意事项  251

15.8 消息队列实验  252

15.9 实验现象  256

第16章 信号量  258

16.1 信号量的基本概念  258

16.1.1 二值信号量  258

16.1.2 计数信号量  259

16.1.3 互斥信号量  259

16.1.4 递归信号量  259

16.2 二值信号量的应用场景  260

16.3 二值信号量的运作机制  260

16.4 计数信号量的运作机制  261

16.5 信号量控制块  262

16.6 常用的信号量函数  263

16.6.1 信号量创建函数  263

16.6.2 信号量删除函数  268

16.6.3 信号量释放函数  268

16.6.4 信号量获取函数  271

16.7 信号量实验  273

16.7.1 二值信号量同步实验  273

16.7.2 计数信号量实验  277

16.8 实验现象  282

16.8.1 二值信号量实验现象  282

16.8.2 计数信号量实验现象  283

第17章 互斥量  284

17.1 互斥量的基本概念  284

17.2 互斥量的优先级继承机制  284

17.3 互斥量的应用场景  287

17.4 互斥量的运作机制  287

17.5 互斥量控制块  288

17.6 互斥量函数  289

17.6.1 互斥量创建函数xSema-phoreCreateMutex()  289

17.6.2 递归互斥量创建函数xSemaphoreCreateRecur-siveMutex()  292

17.6.3 互斥量删除函数vSema-phoreDelete()  293

17.6.4 互斥量获取函数xSema-phoreTake()  293

17.6.5 递归互斥量获取函数xSemaphoreTakeRecur-sive()  299

17.6.6 互斥量释放函数xSema-phoreGive()  301

17.6.7 递归互斥量释放函数xSemaphoreGiveRecur-sive()  304

17.7 互斥量实验  307

17.7.1 模拟优先级翻转实验  307

17.7.2 互斥量降低优先级翻转危害实验  312

17.8 实验现象  318

17.8.1 模拟优先级翻转实验现象  318

17.8.2 互斥量降低优先级翻转危害实验现象  318

第18章 事件  320

18.1 事件的基本概念  320

18.2 事件的应用场景  321

18.3 事件的运作机制  321

18.4 事件控制块  323

18.5 事件函数  323

18.5.1 事件创建函数xEvent-GroupCreate()  323

18.5.2 事件删除函数vEvent-GroupDelete()  325

18.5.3 事件组置位函数xEvent-GroupSetBits()(任务)  326

18.5.4 事件组置位函数xEvent-GroupSetBitsFromISR()(中断)  330

18.5.5 等待事件函数xEvent-GroupWaitBits()  332

18.5.6 清除事件组指定位函数xEventGroupClearBits()与xEventGroupClearBits-FromISR()  337

18.6 事件实验  338

18.7 实验现象  343

第19章 软件定时器  344

19.1 软件定时器的基本概念  344

19.2 软件定时器的应用场景  345

19.3 软件定时器的精度  345

19.4 软件定时器的运作机制  346

19.5 软件定时器控制块  348

19.6 软件定时器函数  349

19.6.1 软件定时器创建函数  349

19.6.2 软件定时器启动函数  352

19.6.3 软件定时器停止函数  356

19.6.4 软件定时器任务  358

19.6.5 软件定时器删除函数  365

19.7 软件定时器实验  366

19.8 实验现象  371

第20章 任务通知  372

20.1 任务通知的基本概念  372

20.2 任务通知的运作机制  372

20.3 任务通知的数据结构  373

20.4 任务通知函数  374

20.4.1 发送任务通知函数  374

20.4.2 获取任务通知函数  391

20.5 任务通知实验  398

20.5.1 任务通知代替消息队列  398

20.5.2 任务通知代替二值信号量  404

20.5.3 任务通知代替计数信号量  409

20.5.4 任务通知代替事件组  414

20.6 实验现象  419

20.6.1 任务通知代替消息队列实验现象  419

20.6.2 任务通知代替二值信号量实验现象  420

20.6.3 任务通知代替计数信号量实验现象  420

20.6.4 任务通知代替事件组实验现象  421

第21章 内存管理  422

21.1 内存管理的基本概念  422

21.2 内存管理的应用场景  423

21.3 内存管理方案详解  424

21.3.1 heap_1.c  424

21.3.2 heap_2.c  428

21.3.3 heap_3.c  436

21.3.4 heap_4.c  438

21.3.5 heap_5.c  448

21.4 内存管理实验  451

21.5 实验现象  455

第22章 中断管理  456

22.1 异常与中断的基本概念  456

22.1.1 中断的介绍  457

22.1.2 和中断相关的术语  457

22.2 中断管理的运作机制  458

22.3 中断延迟的概念  459

22.4 中断管理的应用场景  460

22.5 ARM Cortex-M的中断管理  460

22.6 中断管理实验  462

22.7 实验现象  470

第23章 CPU利用率统计  471

23.1 CPU利用率的基本概念  471

23.2 CPU利用率的作用  471

23.3 CPU利用率统计  472

23.4 CPU利用率统计实验  473

23.5 实验现象  478

附录  479

IoT

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:excel表格内单元格加宽的方法(excel表格单元格怎么加宽)
下一篇:室内定位系统算法--无线时钟同步的比较(基于距离相关的定位算法)
相关文章