uCOS-II在51单片机上的移植
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
功能
处理临界段方式选择 堆栈增长方向 进入临界区 退出临界区 就绪态最高优先级任务运行 任务级任务切换 中断级任务切换 时钟节拍 任务堆栈初始化
表7-1 需要修改的关键函数和宏定义
6
7.1.6 INCLUDES.H
* * * * * * 文件名 : INCLUDES.H * 作者 : Jean J. Labrosse ****************************************************************************/
9
7.1.8 OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()
临界代码的概念。 uC/OS-II定义的两个宏。
{ OS_ENTER_CRITICAL(); /* µC/OS-II 临界代码段 */ OS_EXIT_CRITICAL(); }
#define OS_ENTER_CRITICAL() EA=0 #define OS_EXIT_CRITICAL() EA=1 #define OS_ENTER_CRITICAL() \
例如,任务A和任务B都要调用函数Swap(), 而该函数又使用了全局变量temp。于是当任 务A调用Swap()函数期间,系统发生了任务 切换而使任务B也调用了Swap(),那么任务B 将要改变全局变量temp的值,使任务A传递 给全局变量temp的值丢失而出现错误。
一般来说,一个可重入函数应该在函数中只 使用局部变量,因为函数的局部变量存储在 任务的堆栈中,所以可保证不同的任务在调 用同一个函数时不会发生冲突。
/ ******************* 与处理器相关的代码 ********************/ #define OS_CRITICAL_METHOD ?? #if OS_CRITICAL_METHOD = = 1 #define OS_ENTER_CRITICAL() ?? #define OS_EXIT_CRITICAL() ?? #endif
三种实现方法。 asm(“PUSH PSW”); asm(“DI”); 方法1: #define OS_EXIT_CRITICAL() \ 在OS_ENTER_CRITICAL()中调用处理器指令来禁止中断,以及在 OS_EXIT_CRITICAL()中调用允许中断指令。 asm(“POP PSW”); void some_ucos_ii_service() 方法2: { 是先将中断禁止状态保存到堆栈中,然后禁止中断。 OS_CPU_SR cpu_sr; 方法3: cpu_sr = get_processor_psw(); 有些编译器提供扩展功能,可以得到当前处理器状态字的值。
3
7.1.3 系统栈与任务栈的关系
有些处理器对于堆栈的设置有特殊的要求,即要求堆栈必须设置在一个特定的 区域,比如片内RAM。由于片内的RAM极其有限,不可能把应用程序中所有 任务的堆栈都设置在片内RAM中,所以就只能把应用程序中各个任务堆栈的内 容存放在片外RAM中,而只在片内RAM中设置一个公用的堆栈。
disable_interrupts(); /* µC/OS-II 临界代码段 */ set_processor_psw(cpu_sr); }
10
7.1.9 OS_STK_GROWTH
绝大多数的微处理器和微控制器的堆栈是从上往下长的。但是某些处理器
是用另外一种方式工作的。µC/OS-Ⅱ被设计成两种情况都可以处理,只要 在结构常量OS_STK_GROWTH(在OS_CPU.H中) 中指定堆栈的生长方式 (如下所示)就可以了。
uC/OS-II是通过硬件中断来实现系统时钟, 并在时钟中断服务程序中来处理与时间相关 的问题的。因此,用户所选用的处理器必须 具有响应中断的能力。 一般情况下应该使用硬件定时器来作为 时钟中断源,这个定时器可以是与微处 理器集成在一个芯片上的,也可以是分 立的。
2
7.1.2 什么是可重入代码
可重入的代码指的是一段代码(比如:一个函数)可以被多个任务同时调
#include "os_cpu.h" #include "os_cfg.h" #include "ucos_ii.h" #include <reg51.h> #include <string.h>
7
7.1.7 OS_CPU.H
OS_CPU.H中包括与处理器相关的常量、宏以及类型。
/******************* 数据类型 (与编译器相关的内容) ********************/ typedef unsigned typedef unsigned typedef signed typedef unsigned typedef signed typedef unsigned typedef signed typedef float typedef double typedef unsigned char char char int int long long BOOLEAN; INT8U; INT8S; INT16U; INT16S; INT32U; INT32S; FP32; FP64; OS_STK;
1
7.1.1移植uC/OS-II满足的条件
处理器的C编译器能产生可重入代码。 在程序中可以打开或者关闭中断。 处理器支持中断,并且能产生定时中断(通常在10-100Hz之
间)。 处理器支持能够容纳一定量数据的硬件堆栈(可能达几KB) 处理器有将堆栈指针和其他CPU寄存器存储和读出到堆栈(或者 内存)的指令。
#if OS_CRITICAL_METHOD = = 2 #define OS_ENTER_CRITICAL() ?? #define OS_EXIT_CRITICAL() ?? #endif
#if OS_CRITICAL_METHOD = = 3 #define OS_ENTER_CRITICAL() ?? #define OS_EXIT_CRITICAL() ?? #endif #define OS_STK_GROWTH #define OS_TASK_SW() 1 ???
函数/宏定义
宏定义 宏定义 宏定义 宏定义 函数 函数 函数 函数 函数
所在文件
OS_CPU.H OS_CPU.H OS_CPU.H OS_CPU.H OS_CPU_A.ASM OS_CPU_A.ASM OS_CPU_A.ASM OS_CPU_A.ASM OS_CPU_C.C
语言
C语言 C语言 C语言 C语言 汇编 汇编 汇编 汇编 C语言
13
7.1.11.1 OSTaskStkInit()
OSTaskCreate()和OSTaskCreateExt()通过调用OSTaskStkInt()来初始化任务的堆 栈结构,因此,堆栈看起来就像刚发生过中断并将所有的寄存器保存到堆栈中的情 形一样。 编写OSTaskStkInit()函数的第一步就是堆栈设计。需要考虑以下因素: ① CPU自动入栈的寄存器及压栈顺序。 ② 需要额外保存哪些寄存器。 ③ 所采用的编译器对形式参数的传递方法。 ④ 堆栈的增长方向。 ⑤ 堆栈指针是指向下一个可用空间还是指向上次入栈数据。 ⑥ 所采用的CPU是否存在系统堆栈。
务自己的堆栈区中。入栈工作完成后,就是把下一 个将要运行任务的当前状态从该任务的堆栈中重新 装入CPU寄存器,并开始下一个任务的运行,这个 过程叫任务切换。
12
7.1.11 OS_CPU_C.C
OS_CPU_C.C文件包含10个C函数:
OSTaskStkInit()
OSTaskCreateHook() OSTaskDelHook() OSTaskSwHook() OSTaskIdleHook() OSTaskStatHook() OSTimeTickHook() OSInitHookBegin() OSInitHookEnd() OSTCBInitHook() 唯一必要的函数是OSTaskStkInit(),其它九个属于钩子函数,必须得声明但没 必要包含代码。
使得项目中的每个.c文件不用分别考虑它实际上需要那些头文件。 它会包含一些不相关的头文件 INCLUDES.H 是一个头文件,它在所有的.c文件的第一行被包含。 #include “includes.h”
uC/OS-II
/*************************************************************************** 实时内核 (c) Copyright 1992-1998, Jean J. Labrosse, Plantation, FL 版权所有 MCU-51 专用代码 KEIL C51大模式编译
用,而不必担心会破坏数据。 也就是说,可重入型函数在任何时候都可以被中断执行,过一段时间以后 又可以继续运行,而不会因为在函数中断的时候被其他的任务重新调用, 影响函数中的数据。 可重入的代码的实现主要是编程技术,所有嵌入式集成开发环境都能产生 可重入的代码。
int temp; void Swap(int *x, int *y) { temp = *x; *x = *y; *y = temp; }
图7-2 uC/OS-II的文件结构
5
7.1.5 需要修改的关键函数和宏定义
名称
OS_CRITICAL_METHOD OS_STK_GROWTH OS_ENTER_CRITICAL() OS_EXIT_CRITICAL() OSStartHighRdy() OSCtxSw() OSIntCtxSw() OSTickISR() OSTaskStkInit()
CPU 系统堆栈 被中止运行的任 务堆栈
……
SP
……
被运行的任务堆栈
……
片外的RAM用来存放任务堆栈,片内RAM 中是系统的公共堆栈,当系统运行某个任务 时,就要把该任务的堆栈映像复制到系统堆 栈中;而在中止这个任务时,再把系统堆栈 中的内容复制回任务堆栈映像中。
图7-1 系统栈与任务栈的关系
4
7.1.4 uC/OS-II文件结构
uc/os-II 操作系统的移植
所谓操作系统的移植,是指使一个实时操作系统能够在某个特定的 微处理器平台上运行。 COS-II的主要代码都是由标准的C语言写成的,移植方便。但仍需 要用汇编语言写一些与处理器相关的代码,这是因为µC/OS-Ⅱ在读 写处理器寄存器时只能通过汇编语言来实现。 移植的主要工作是修改部分与处理器硬件相关的代码。
⑦ 堆栈深度。
任务按函数形式编写,但永远不被调用,而是通过模仿中断的方式来运行其中的代码。既然任务通过模 仿中断的方式来进行,而且拥有自己单独的任务栈,那么需要做的就是执行中断返回指令,让任务中的 内容出栈,让系统觉得该任务(或者说是所谓的“函数”)刚刚被中断过,现在需要继续执行。但在系 统刚开始运行的时候,任务是没有被系统中断过的,也没有被切换过,任务栈里没有内容。所以需要通 过OSTaskStkInit()来初始化任务栈,模拟一次压栈动作,使得系统认为任务刚刚被中断过。 14
置OS_STK_GROWTH为0表示堆栈从下往上长。
置OS_STK_GROWTH为1表示堆栈从上往下长。
11
7.1.10 OS_TASK_SW()
OS_TASK_SW()是一个宏,它是在µC/OS-Ⅱ从低优先级任务切换到最高优先级任 务时被调用的。 在µC/OS-Ⅱ中,处于就绪状态的任务的堆栈结构看起来就像刚发生过中断并将所 有的寄存器保存到堆栈中的情形一样。换句话说,µC/OS-Ⅱ要运行处于就绪状态的 任务必须要做的事就是将所有处理器寄存器从任务堆栈中恢复出来,并且执行中断的 返回。为了切换任务可以通过执行OS_TASK_SW()来产生中断。大部分的处理器会提 供软中断或是陷阱(TRAP)指令来完成这个功能。 例如,在Intel或者80x86处理器上可以使用INT指令。但是中断处理向量需要指向 OSCtxSw()。 一些处理器并不提供软中断机制。在这种情况下,用户需要尽自己的所能将堆栈结 当多任务内核决定运行另外的任务时,它保存正在 构设置成与中断堆栈结构一样,再用函数调用方式来实现任务切换,也就是说通过函 运行任务的当前状态,即CPU寄存器中的全部内容。 这些内容保存在任务的当前状态保存区,也就是任 数来模仿软中断指令。如#define OS_TASK_SW() OSCtxSw()