⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chapter1.txt

📁 ucos的PDF书籍、2.00源码以及我的学习心得
💻 TXT
字号:
1.00 Installing uC/OS-II
由于作者写此书是在20世纪90年代,当时软驱还比较流行,因此作者提供了一个通过软驱进行安装的INSTALL.BAT批处理文件。作者在书中所讲述的安装方法也是基于这个批处理文件进行的。显然,对于现在的许多机器用作者书中所描述的方法将不可能完成安装(现在的机器上基本都不安装软驱)。不过,我们可以根据作者的批处理文件,通过手工安装的方式,来完成安装。
具体步骤如下:
1、下载ucosii的压缩包到本地机;
2、解压后找到UCOS-II.EXE文件;
3、在所要安装的目录下建立SOFTWARE文件夹;
4、拷贝UCOS-II.EXE至SOFTWARE文件夹下;
5、在DOS中切换至SOFTWARE目录,并运行以下命令:UCOS-II -d -n \SOFTWARE;
6、第5步执行完毕后,就可以看作安装过程完毕了,当然也可以像作者一样删除UCOS-II.EXE文件作为结束。

1.03 Global Variables
#ifdef 	xxx_GLOBALS
#define	xxx_EXT
#else
#define	xxx_EXT		extern
#endif
这种方法不错!

1.04 OS_ENTER_CRITICAL() and OS_EXIT_CRITICAL()
作者提供了两种开关中断的方法:
OS_CRITICAL_METHOD == 1时,OS_ENTER_CRITICAL() 通过汇编指令CLI(即Clear Interrupt)完成;OS_EXIT_CRITICAL()通过汇编指令STI(即Set Interrupt)完成。通过此种方式有一点不足,即执行完OS_ENTER_CRITICAL(); ... OS_EXIT_CRITICAL();函数对之后,不论在之前处理器状态如何,中断都会打开。
OS_CRITICAL_METHOD == 2时,OS_ENTER_CRITICAL()通过汇编指令{PUSHF, CLI}完成,注意这里多出的PUSHF指令实际上是在保存处理器的状态;OS_EXIT_CRITICAL()通过汇编指令POPF完成,实际上就相当于还原之前保存的处理器状态。可以发现,通过此种方式,在执行完OS_ENTER_CRITICAL(); ... OS_EXIT_CRITICAL();函数对后,处理器的状态将保持与之前的一致。
从以上两种方法的描述可以看出:方法1有效率上的优势,方法2则更加稳定。

1.05.01 PC Based Services,Character Based Display
void far *MK_FP(unsigned seg, unsigned off)	得到段地址为seg,偏移量为off的远程指针
此函数在各PC_Dispxxx()中都有所引用,用于得到显示缓冲区中特定地址的远程指针。

1.05.03 PC Based Services, Miscellaneous
关于定时器时钟频率设置问题,研究一下以下几个式子:
~~1000ms / 18.20648 = 54.925ms;	
每54.925ms产生一次定时器中断,1s产生约18次中断。这是在DOS模式下定时器的中断频率。
~~54.925ms / 65535 * 59659 = 50ms;	
这就是为什么作者说"Had the chip been initialized with a divide by 59659, the tick rate would have been a very nice 20.000 Hz!"
~~200Hz / 11 = 18Hz;			
作者在uc/OS环境中将定时器的中断频率设置为200Hz,即1s产生200次定时器中断。但是为了使一些需要在DOS下运行的程序可以正常运行,每11次定时器中断,呼叫一次DOS模式下的定时器中断处理函数,这样1s中仍然呼叫18次该定时器中断处理函数,与DOS模式下的情况一致。
~~count * (54.9246ms / 65535) = 1000ms / freq -> count = (1000ms * 65535 / 54.9246ms) / freq -> count = 1193180 / freq
最后所推得的count = 1193180 / freq是将定时器中断频率设置为freq时,决定计数器数值的公式。不过,此公式与源文件PC.c中函PC_SetTickRate中的公式--count = (INT16U)(((INT32U)2386360L / freq + 1) >> 1)--不同。但是再仔细研究一下会发现,源文件中的公式等效于count = (INT16U)(1193180 / freq + 0.5),这实际上相当于完成一个四舍五入的功能!

1.07.01 Example #1, main()
~~PC_DOSSaveReturn
在书中,L1.6(2)处OS_TickDOSCtr = 8应改为OS_TickDOSCtr = 1;这样,就与正文与源文件PC.c一致了。
PC_DOSSaveReturn函数完成的工作:
1、初始化OSTickDOSCtr为1,该变量为外部变量,在OS_CPU.h中定义;
这样做主要原因在于:从前面的叙述中知道,为了使一些需要在DOS下运行的程序可以正常运行,我们在uc/OS环境下(1s呼叫200次时间中断处理函数)要模仿DOS环境中调用定时器中断处理函数的情况(1s呼叫18次),这一任务交由uc/OS的定时器中断处理函数OSTickISR()执行。OSTickISR完成此项操作是借助OSTickDOSCtr变量完成的。函数在每次呼叫完DOS环境中的时间处理函数后,将OSTickDOSCtr赋值为11。在之后的响应过程中,首先将OSTickDOSCtr自减1,然后判断自减后的变量值是否为0,若是,则再次呼叫DOS环境中的时间处理函数同时将OSTickDOSCtr赋值为11,依此循环。
由于uc/OS下的定时器中断频率为200Hz,故1s内将会调用200次函数OSTickISR,而由于每调用11次OSTickISR会调用1次DOS模式下的定时器中断处理函数,因此1s内共调用200 / 11 = 18次此中断函数,这样也就达到了模拟DOS环境下定时器中断处理情况的目的。
讲了这么多,那为什么要初始化OSTickDOSCtr呢?根据以上的讨论可知,在每次响应定时器中断调用OSTickISR时,都要先将OSTickDOSCtr自减1,然后再比较值其是否为0。如果不对OSTickDOSCtr进行初始化,那么根据编译器对外部变量的默认初始化,OSTickDOSCtr的值为0。这样,在响应定时器中断,调用OSTickISR函数时,OSTickDOSCtr会从0自减1变成255(OSTickDOSCtr是INT8U类型的变量)。为避免此种情况,故而对OSTickDOSCtr进行初始化,这里作者初始化的值为1,但据我自己的理解,其实只要是1到11之间的整数值都可以,它们的区别仅仅在于首次调用DOS模式下定时器中断处理函数的时机。
2、保存DOS模式下的定时器中断处理函数;
这里将该中断处理函数保存到向量VECT_DOS_CHAIN中,此向量对应的地址为0x81。在OS_CPU_A.ASM里的OSTickISR函数中,当需要调用DOS模式下的定时器处理函数时(OSTickDOSCtr = 0时),通过指令INT 0x81调用的函数就是这里所保存的函数。
3、用setjmp函数设置返回点。
这里,我有点怀疑作者使用setjmp/longjmp的必要性。我觉得应该可以不用setjmp/longjmp函数,而通过将PC_DOSSaveReturn函数if语句里的内容剪切
至PC_DOSReturn函数中的方式返回DOS环境。

1.07.02 Example #1, TaskStart()
~~OSStatInit()的工作流程:
1、等待两个定时器中断,以保证该函数的运行与定时器同步;
2、将外部变量OSIdelCtr赋值为0,这是一个32位变量,充当计数器的作用;
3、等待1s的延时,在此段时间里,TaskStart进程将会在OSStatInit处被挂起;
4、由于在TaskStart任务被创建之前,已经通过OSInit函数创建了两个任务:OSTaskIdel(系统空闲进程)和OSTaskStat(计算CPU利用率的进程),而OSTaskStat进程在OSStatRdy变量为FALSE时被一直挂起,故而此时系统没有其他有用进程,系统将运行空闲进程OSTaskIdel;
5、OSTaskIdel的任务很简单:循环对外部变量OSIdelCtr自增1。在OSStatInit延时的这1s里,CPU将只运行这一任务;
6、在1s延时结束之后,TaskStart进程被唤醒。此时将OSIdelCtr的值赋给外部变量OSIdelCtrMax,看作在1s内OSIdelCtr可以自增到的最大值(因为以后在1s的时间内,系统中将不可能总是仅有OSTaskIdel一个进程在执行。OSTaskIdel只在没有其他有用进程运行时,才会被系统调用执行),同时将OSStatRdy赋为TRUE,唤醒OSTaskStat进程;
7、在此之后,每隔1s,系统将会调用一次OSTaskStat进程对CPU使用率进行计算。计算的公式为:
CPUUsage = (1 - OSIdelCtr / OSIdelCtrMax)  * 100%

1.08 Example #2
~~stack checking的原理:
1、在创建Task时,除完成一些基本的操作外还需要完成对该Task的Task Stack的初始化,即将该Stack的所有项初始化为0;
2、在Task运行过程中,如果需要使用Task Stack的资源,则按自顶向下的方向顺序使用;
3、当需要进行stack checking时,设置一个指针自底向上进行扫描,直到遇到不为0的项停止,在此过程中所扫描过的项的个数即为空闲Stack项的个数;
4、由于在一个Task创建时,其Task Stack的大小是固定的,因此用其Stack总的大小减去空闲Stack项的个数,就是已用的Stack项的个数。

1.09 Example #3
~~uC/OS中各文件的组织:
uC/OS中的文件主要分为两大部分:可移植部分和与具体硬件相关的部分。
在作者所给例程中,可移植的部分即SOFTWARE/UCOS-II/SOURCE文件夹下的.c文件,当将uC/OS移植至其他硬件结构的系统上时,这些文件不需要做任何的修改;与具体硬件相关的部分即SOFTWARE/UCOS-II/IX86L文件夹下的文件(.c和.asm文件),这些文件是作者为了将uC/OS移植到80x86CPU上而写的,当将uC/OS移植到其他硬件结构的系统上时,这一部分的文件需要根据所移植的系统的特点重新书写。
以上所讨论的两部分源文件由SOFTWARE/UCOS-II/SOURCE文件夹下的UCOS-II.h头文件来统一管理。在该文件的最后,注释为"Target Specific Functions"的函数声明即为与硬件相关部分的函数声明;而其余的函数声明则是可移植部分的函数声明。当将uC/OS移植到其他的系统上时,我们只需要关心与硬件相关部分的函数声明,因此这里着重分析一下在UCOS-II.h文件中注释为"Target Specific Functions"的那部分声明。
uC/OS中在系统移植时需要我们自己根据硬件结构进行定义的函数有以下几个:
void        OSCtxSw(void);
void        OSIntCtxSw(void);
void        OSStartHighRdy(void);
void        OSTaskCreateHook(OS_TCB *ptcb);
void        OSTaskDelHook(OS_TCB *ptcb);
void        OSTaskStatHook(void);
void       *OSTaskStkInit(void (*task)(void *pd), void *pdata, void *ptos, INT16U opt);
void        OSTaskSwHook(void);
void        OSTickISR(void);
void        OSTimeTickHook(void);
在作者提供的例程中,OSCtxSw、OSIntCtxSw、OSStartHighRdy以及OSTickISR在文件OS_CPU _ASM.asm中定义,而OSTaskStkInit以及所有的Hook函数在文件OS_CPU.c中定义。在这一节中,我们只讨论Hook函数,对于其他的函数目前尚无能力讨论。
xxxxHook函数是作者提供给使用者用于扩展响应内部函数xxxx功能的函数(唯一例外的是OSTaskSwHook,它在OSStartHighRdy中被调用),现以OSTaskStatHook函数为例来讨论其使用原理。
对于内部函数OSTaskStat,作者仅仅直接为使用者提供了一项功能即计算CPU的使用情况的功能,但是为了使该函数的使用者能够对其功能进行进一步的拓展,作者在完成实现上述功能的操作之后,添加了一条调用OSTaskStatHook函数的语句,这样,如果使用者需要对OSTaskStat函数进行拓展时,只需要定义OSTaskStatHook函数并将完成相应功能的代码添加至该函数的函数体中即可,而如果使用者不打算对函数做任何拓展,他仍然需要定义OSTaskStatHook函数,只是保持该函数的函数体为空就行了。在作者所给的例程中,作者在OS_CPU.c文件中定义的各Hook函数均为空函数,但为了保持灵活性,作者将这些Hook函数用一个名为OS_CPU_HOOKS_EN的宏变量进行管理。如果应用程序编写者希望使用作者例程中提供的Hook函数,那么他需要在其应用程序的OS_CFG.h文件中,将OS_CPU_HOOKS_EN定义为1;而如果应用程序编写者希望对内部函数进行一定的的扩展(如本节中的应用程序),那么他需要在OS_CFG.h文件中,将OS_CPU_HOOKS_EN定义为0,以表明他将自己完成对各Hook函数的定义。
对比本节示例程序与上两节的程序的OS_CFG.h文件可以发现:本节OS_CFG.h中的OS_CPU_HOOKS_EN被定义为0,这表明本节的应用程序对一些内部函数的功能进行了拓展。



			
	



	

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -