ucos2源码分析---内核部分(三)

本文详细分析了uCOS2内核的CPU、Lib与OS部分的源码,包括uC-CPU中关于CPU配置、数据类型的定义以及临界区管理;uC-LIB提供的内存管理、字符处理功能;以及uCOS-II部分的临界区实现、内存池和汇编中的关键字。同时,文章介绍了文件包含、内存池、汇编关键字EXPORT的使用,并探讨了任务切换、临界区和中断处理的相关知识。

注:本文章参考朱有鹏单片机课程课件

一、uCOS2内核部分源码概述

1.1 主要包含如下三个文件夹

1)uC-CPU :主要是和CPU硬件相关的
2)uC-LIB:主要是一些可能会使用到的库,比如内存相关、字符相关
3)uCOS-II:这个是真正和内核相关的代码

1.2 注意点

(1).asm的汇编文件
(2)学习技巧:一边分析一边写注解
(3)一个有意思的疑问:从简单(边角)到难(核心)还是从难到简单

二、uC-LIB部分源码分析

在这里插入图片描述
lib_def.h : 文件中定义了很多宏,这些宏要么是对一些常数的宏定义(譬如0 1 0xff等),要么是对一些可能用到的和环境有关的数值的定义(譬如一个月多少天,一天多少小时,一小时多少分等等)
lib_mem.h :文件中包含了memory出错时的error code 以及一些配置宏,如:
LIB_MEM_CFG_ARG_CHK_EXT_EN 类似于这种宏在uCOS中叫做配置宏,这些宏的作用是用来配置uCOS内核的可选项目。uCOS本身设计的时候设计了很多属性,但是这些属性是可选使能或者不使能的,这样我们就可以通过一些配置宏来配置项目,在编译的时候(预处理)由编译器(预处理器)来帮我们把uCOS内核的这些特性加上或者去掉。
还有一些内存处理函数的声明,比如:复制、清除、设置等
lib_mem.c: 这个文件里面的就是对内存处理的各个函数定义,比如 Mem_Init 、Mem_Clr、Mem_Set、Mem_Copy等。
lib_str.c : 这个文件里面主要就是实现对字符的处理,比如:Str_Len、Str_Copy、Str_Cmp等。
lib_mem_a.asm: 这文件是在ports目录下,是一个汇编文件,主要实现的是一个Mem_Copy的功能。
1)该文件实现了一个函数mem_cpy,这个函数是用来进行内存的拷贝的。内存的拷贝是在RTOS中非常重要,内核实现也会需要用到内存拷贝,所以效率要求比较高,所以用汇编来实现。
(2)为什么uCOS2中有些东西要用汇编来实现?2个原因:一个是效率更高,另一个是不得不用汇编因为C实现不了。

知识点1:文件包含的三种方法

1、#include<xxx.h>
这种方式下,预处理器通常只会去系统指定目录下查找。如果需要包含标准库头文件或者实现版本所提供的头文件,可以使用这种方式。

2、#include"xxx.h"
这种方式下,预处理器通常优先在当前目录下寻找,即当前工程下的其他源文件的目录。如果在当前目录下没有找到,那么预处理器也会搜索系统的 include 路径。如果需要包含针对程序所开发的源文件,则可用这种方式。

3、#include"xx\xx.h"
文件名中包含了路径,则预处理器只会到该目录下寻找。

版权声明:本文为CSDN博主「蓝晴明」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u012017396/article/details/104006112

知识点2: 内存池

内存池就是在程序启动时,预先向堆中申请一部分内存,交给一个管理对象。在程序运行中,需要时向管理对象“借”,不需要时“还”给管理对象。
更多详情请参考 内存池简单实现(一)

知识点3: 汇编中的EXPORT关键字

import,标识符表明要调用的函数为本模块外部定义的
export,标识符表示本模块中定时的符号可以为外部模块使用

总结

对于Lib这部分的源码分析,我们发现这部分代码的作用主要就是提供内存处理、字符处理和一些常用的宏定义的接口,方便我们其他地方进行调用。

三、uC-CPU部分源码分析

3.1 、cpu_def.h

该文件的作用主要是定义了CPU的字大小、大小端、以及临界区相关的宏。

这里主要是定义了临界区的几种方式

                                                        /* --------------- CPU CRITICAL SECTION METHODS --------------- */
#define  CPU_CRITICAL_METHOD_NONE                  0    /*                                                              */
#define  CPU_CRITICAL_METHOD_INT_DIS_EN            1    /* DIS/EN       ints.                                           */
#define  CPU_CRITICAL_METHOD_STATUS_STK            2    /* Push/Pop     int status onto stk.                            */
#define  CPU_CRITICAL_METHOD_STATUS_LOCAL          3    /* Save/Restore int status to local var.                        */

3.2 、cpu.h

该文件中主要作用:
1)定义了一些标准的数据类型
2)定义临界区进入退出宏
CPU_CRITICAL_ENTER()宏用来进入临界区,实现其实就是函数内部关闭中断,然后备份CPSR到局部变量cpu_sr中即可。
CPU_CRITICAL_EXIT()宏用来退出临界区,

#define  CPU_CFG_CRITICAL_METHOD        CPU_CRITICAL_METHOD_STATUS_LOCAL

#define  CPU_CRITICAL_ENTER()           {
     
      cpu_sr = CPU_SR_Save(); }
#define  CPU_CRITICAL_EXIT()            {
     
      CPU_SR_Restore(cpu_sr); }

所对应的汇编在cpu_a.asm中实现
在这里插入图片描述
这种方式就是通过Save/Restore 中断状态进行临界区进出,也就是3.1中最后的一种方式
3)进行函数声明
4)中断源的定义,这里目前有16个
5)一些特定寄存器的定义,比如:

在这里插入图片描述
volatile的作用: 作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值
6)定义了CPU 寄存器一些特定的位
在这里插入图片描述
7)配置了一些error信息,就是在CPU中必须要配置的项,如果没有配置就会报错。
在这里插入图片描述

3.3 、cpu_a.asm

该文件的作用是一个用汇编实现了如下的功能,并导出供其他使用。
开关中断、保存恢复中断状态、计算第一个二进制数前0的个数、位反转、等待中断、等待异常。
在这里插入图片描述

3.4、cpu_c.c

这个文件中涉及位带访问的几个函数定义,如位带清除、位带设置、中断源关闭/使能、中断优先级设置/获取。

1)下面三行在宏定义配置判断成功时,其实相当于定义了一个函数内的局部变量,类型是CPU_SR,变量名是cpu_sr。定义这个局部变量的作用,是用来配合后面的2个宏。

#if (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL)
    CPU_SR      cpu_sr;
#endif

(2)RTOS中实现临界区常用的有三种方法,uCOS2本来是想要三种方式都支持的,所以在宏定义的时候定义了三种,但是实际上方式1和2都不靠谱,实际全是用的3,1和2名存实亡。所以CPU_CRITICAL_ENTER()和CPU_CRITICAL_EXIT()中直接使用了方式3,但是方式3的这2个宏依赖于一个名叫cpu_sr的局部变量。如果没有这个局部变量则会编译时报错,所以只要函数用到了这2个宏,就得在函数前面加上(1)中的三行。

知识点1: 临界区

临界区指的是一个访问共用资源(例如:共用设备或是共用存储器)的程序片段,而这些共用资源又无法同时被多个线程访问的特性。

当有线程进入临界区段时,其他线程或是进程必须等待(例如:bounded waiting 等待法),有一些同步的机制必须在临界区段的进入点与离开点实现,以确保这些共用资源是被互斥获得使用,例如:semaphore。只能被单一线程访问的设备,例如:打印机。

进程进入临界区的调度原则是:

1、如果有若干进程要求进入空闲的临界区,一次仅允许一个进程进入。

2、任何时候,处于临界区内的进程不可多于一个。如已有进程进入自己的临界区,则其它所有试图进入临界区的进程必须等待。

3、进入临界区的进程要在有限时间内退出,以便其它进程能及时进入自己的临界区。

4、如果进程不能进入自己的临界区,则应让出CPU,避免进程出现“忙等”现象。

知识点2: 为什么有些宏定义在头文件中,有些定义在源文件中
结论:主要看可能使用的范围决定,详细可参考C项目中变量、宏定义、结构体等声明定义位置问题(头文件、源文件)

知识点3: STM32的位带操作
结论: 就是将每一个比特膨胀成一个32位的字,也就是给原本的每一个比特位都对应上了一个地址,我们直接通过地址访问的方式进行赋值即可。更多可参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值