(计算机应用技术专业论文)基于s3c44b0 x的μcosⅡ的研究与实现.pdf_第1页
(计算机应用技术专业论文)基于s3c44b0 x的μcosⅡ的研究与实现.pdf_第2页
(计算机应用技术专业论文)基于s3c44b0 x的μcosⅡ的研究与实现.pdf_第3页
(计算机应用技术专业论文)基于s3c44b0 x的μcosⅡ的研究与实现.pdf_第4页
(计算机应用技术专业论文)基于s3c44b0 x的μcosⅡ的研究与实现.pdf_第5页
已阅读5页,还剩42页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

中南民族大学硕士学位论文 i 摘 要 c/os-是著名的、源码公开的实时内核,是专为嵌入式应用设计的。它具有商业 级的性能和安全性。但是,它毕竟只是一个操作系统内核,必须移植到实际应用系统的 硬件平台上,所以有必要对其移植方法进行研究。另外,它在某些方面还存在着一定的 局限性,有必要对其进行改进,才能满足应用需求。 c/os-规定应用系统最多 64 级优先级。对于较复杂的应用而言,这不足以满足 实际需要。因而有必要对其优先级数进行扩充。另外,c/os-规定所有任务的优先级 必须不同。实际上它完全是根据任务的优先级来进行调度。但有些任务在优先级上并没 有区别,也就是说它们是处于同一级别的,在它们之间采用分时调度策略更加合理。 本文首先基于深圳 embest 公司的 s3cev40 开发板,成功移植了c/os-内核, 分 析了移植过程。然后在分析c/os-就绪表数据结构和算法的基础上,将原来 88 的 优先级数扩充到了 1616 的优先级数,并且在扩充的同时保证了时空效率。在c/os- 优先级调度的基础上,引入了轮转调度的策略,同时保持了c/os-所具有的性能。 本文对所作的移植和改进进行了验证。 实验结果表明, 移植和改进达到了预期目标。 本文也分析了改进之处对系统性能的影响。研究表明,改进之后保持了c/os-的高效 性。这说明改进是有应用价值的。 关键词关键词: 嵌入式操作系统;嵌入式操作系统; c/os-;s3c44b0x;移植;优先级数扩充;轮转调度;移植;优先级数扩充;轮转调度 基于 s3c44b0x 的c/os-的研究与实现 ii abstract c/os- is a well-known open source real-time kernel. it is designed for embedded applications. it has the performance and security of business level. however, it is just only an operating system kernel, and needs to be transplanted onto the hardware platforms of practical application systems. so it is necessary to study the transplant method. in addition, it has some limitations, and needs to be improved to satisfy the application requirement. c/os- provides that a application system has a maximum of 64 priority levels. it isnt sufficient to satisfy the requirement of more complex applications. so it is necessary to expand its number of priority level. in addition, c/os- provides that all tasks have the different priority levels. practically it schedules the tasks fully based on their priority levels. however, some tasks dont have different priority levels, in other words, they should be assigned the same priority level and be scheduled in the time-sharing strategy. this paper transplants c/os- kernel which is based on the s3cev40 evaluation board of embest info然而c/os-的作者建议用户保留 8 个 给c/os-。这样,留给用户的应用程序最多可有 56 个任务。 8)可确定性:绝大多数c/os-的函数调用和服务的执行时间有确定性。也就是 说,用户能知道c/os-的函数调用与服务执行了多长时间。 9)任务栈:c/os-的每个任务都有自己单独的栈。使用c/os-的栈空间校验 函数,可确定每个任务到底需要多少栈空间。 10)系统服务:c/os-提供很多系统服务,例如信号量、互斥信号量、时间标志、 消息邮箱、数据队列、块大小固定的内存的中请与释放及时间管理函数等。 11)中断管理:中断可以使正在执行的任务暂时挂起。如果优先级更高的任务被中 断唤醒, 则高优先级的任务在中断嵌套全部退出后立即执行。 中断嵌套层数可达 255 层。 12)稳定性和可靠性:c/os-是基于c/os 的。c/os 自 1992 年以来已经有数 中南民族大学硕士学位论文 5 百个商业应用。c/os-与c/os 的内核是一样的,只是提供了更多的功能。 1.2 课题研究的背景与完成的工作 1.2.1 课题研究的背景 虽然c/os-有着优良的性能,但是它毕竟只是一个操作系统内核,必须移植到实 际应用的硬件平台上, 因而有必要对其移植进行研究。 另外, 对于某些应用而言, c/os- 还存在着限制,需要改进才能满足应用需求。通过分析c/os-,发现其优先级方面 存在以下限制: 1)优先级数不能超过 64; 2)所有任务优先级必须不同。 由于c/os-中最大任务数和优先级数是一样的, 限制了优先级数也就限制了系统 最大任务数,在相对复杂的实际应用中,这会成为一个制约条件。因此有必要对其进行 扩充,以满足实际需要。另外,c/os-规定所有任务的优先级必须不同,完全根据任 务的优先级来进行调度。但有些任务在优先级上并没有区别,也就是说它们是处于同一 级别的, 在它们之间采用分时调度策略更加合理。 针对c/os-在优先级方面的局限性, 需要对其进行改进。 1.2.2 课题所完成的工作 本课题完成了以下工作: 1)以深圳 embest 公司的 s3cev40 开发板为例,完成了c/os-的移植工作,分 析了c/os-的移植过程; 2)在分析c/os-就绪表数据结构和算法的基础上,结合现有的扩充理论,完整 地实现了 88 到 1616 优先级数的扩充,并对扩充进行了效率分析; 3)在c/os-优先级调度的基础上,引入了轮转调度的策略,给出了现有的实现 方案,并在其基础上进行了改进,分析表明改进之后保持了c/os-的高效性。 基于 s3c44b0x 的c/os-的研究与实现 6 第 2 章 移植 c/os- 所谓移植,就是使一个实时内核能在其它的微处理器或微控制器上运行。为了方便 移植,大部分c/os-的代码是用 c 语言编写的,但是仍需要用 c 语言和汇编语言写 一些与处理器硬件相关的代码。在操作系统启动之前,需要一段代码作为引导,这就是 通常所说的启动代码。本章先介绍移植的硬件平台,然后分析启动代码和移植过程。 2.1 移植硬件平台 本文采用的是深圳 embest 公司的 s3cev40 开发板。它基于 samsung 公司的 s3c44b0x 处理器。embest s3cev40 开发板结构如图 2.1 所示。其硬件特性如下9: 1)电源:dc5v1.5a 供电或由 usb 接 pc 供电,电源指示 led 以及 500ma 保险 丝; 2)2 个串口,其中一个为简单接口,一个为全接线接口,可连接 rs232 modem; 3)1m16bit flash; 4)41m16bit sdram; 5)固态硬盘 16m8bit; 6)4kbit iic bus 的串行 eeprom; 7)lcd 及 tsp 触摸屏接口; 8)外部 ide 硬盘接口; 9)44 用户键盘; 10)usb 设备; 11)10m 以太网接口; 12)microphone 输入口; 13)iis 音频信号输出口,可接双声道 speaker; 14)320*240 带触摸功能的显示屏; 15)4 个 220pin cpu 扩展接口; 16)两个中断按钮,两个 led; 17)20 针 jtag 接口; 18)8 段数码管; 中南民族大学硕士学位论文 7 19)复位开关。 图 2.1 embest s3cev40 开发板结构图 2.2 启动代码的编写 启动代码是芯片复位后进入 c 语言的 main()函数前执行的代码,主要初始化系统, 为后面的程序提供运行环境,因而它是必要的。对于 arm 核的芯片,启动代码一般由 异常向量表、向量中断表和系统初始化代码组成。 2.2.1 异常向量表 异常是由内部或外部源产生的以引起处理器处理的一个事件10。arm 处理器支持 7 种类型的异常。异常出现后,cpu 强制从异常入口地址开始执行程序。 对于 s3c44b0x 处理器而言,0 x00 处为复位入口,通过它启动系统。0 x040 x1c 为 7 个异常入口地址11。 异常入口代码如程序清单 2.1 所示。 向量从上到下依次为复位、 未定义异常、 软件中断异常、 预取指令中止、 预取数据中止、 保留异常、 irq 异常和 fiq 异常。 程序清单 2.1 异常向量表 _start: b resethandler 复位入口 基于 s3c44b0x 的c/os-的研究与实现 8 b handlerundef 未定义异常 b handlerswi 软件中断异常 b handlerpabort 预取指令中止 b handlerdabort 预取数据中止 b . 保留 b handlerirq irq 异常 b handlerfiq fiq 异常 2.2.2 中断向量表 s3c44b0x 的中断控制器可以接受来自 30 个中断源的中断请求。在这些中断源中, eint4/5/6/7、uart0/1 共用一条中断请求线。因此,它可以同时容许 26 个中断12,13。 为了减少中断反应时间,s3c44b0x 提供向量中断模式。在非向量模式下,s3c44b0x 收到中断控制器的 irq 中断请求时会执行 0 x18 处的指令。但是在向量模式下,中断控 制器会在数据总线上加载分支指令,从而对应到每个终端源的向量地址。中断源的向量 地址从 0 x20 到 0 xc0。如程序清单 2.2 所示。程序中“b .”为保留未使用。 程序清单 2.2 中断向量表 vector_branch: ldr pc, =handlereint0 外部中断 0 ldr pc, =handlereint1 外部中断 1 ldr pc, =handlereint2 外部中断 2 ldr pc, =handlereint3 外部中断 3 ldr pc, =handlereint4567 外部中断 4/5/6/7 ldr pc, =handlertick rtc timer tick 中断 b . 保留 b . 保留 ldr pc, =handlerzdma0 dma0 中断 ldr pc, =handlerzdma1 dma1 中断 省略 b . 保留 ldr pc, =handleradc adc 中断 中南民族大学硕士学位论文 9 2.2.3 系统初始化 系统初始化代码主要完成一些硬件、堆栈的初始化工作,并将可读写初始化数据和 零初始化数据从 rom 区拷贝到 ram 区执行,然后跳转到 main()函数14。具体过程为: 关看门狗和中断设置时钟控制寄存器设置内存控制寄存器设置异常模式堆栈指 针复制可读写初始化数据和零初始化数据跳转到 main()函数。系统初始化代码见程 序清单 2.3。 程序清单 2.3:系统初始化 resethandler: # 关闭看门狗 ldr r0, =wtcon ldr r1, =0 x0 str r1, r0 # 屏蔽所有中断 ldr r0, =intmsk ldr r1, =0 x07ffffff str r1, r0 # 设置时钟控制寄存器 ldr r0, =locktime ldr r1, =0 xfff str r1, r0 ldr r0, =clkcon ldr r1, =0 x7ff8 str r1, r0 # 设置内存控制器 add r0, pc, #-(8+.-smrdata) ldmia r0, r1-r13 基于 s3c44b0x 的c/os-的研究与实现 10 ldr r0, =0 x01c80000 stmia r0, r1-r13 # 设置异常模式堆栈指针 mrs r0, cpsr bic r0, r0, #modemask orr r1, r0, #undefmode|noint msr cpsr_cxsf, r1 未定义模式堆栈指针初始化 ldr sp, =undefstack orr r1, r0, #abortmode|noint msr cpsr_cxsf, r1 中止模式堆栈指针初始化 ldr sp, =abortstack orr r1, r0, #irqmode|noint msr cpsr_cxsf, r1 irq 模式堆栈指针初始化 ldr sp, =irqstack orr r1, r0, #fiqmode|noint msr cpsr_cxsf, r1 fiq 模式堆栈指针初始化 ldr sp, =fiqstack orr r1, r0, #svcmode msr cpsr_cxsf, r1 返回到 svc 模式 # 复制可读写初始化数据和零初始化数据 ldr r0, =image_ro_limit 只读段顶端 ldr r1, =image_rw_base 可读写数据段底端 ldr r3, =image_zi_limit 零初始化数据底端 cmp r0, r1 中南民族大学硕士学位论文 11 beq f1 f0: cmp r1, r3 复制可读写数据段段 ldrcc r2, r0, #4 strcc r2, r1, #4 bcc f0 f1: ldr r1, =image_zi_limit mov r2, #0 f2: cmp r3, r1 复制零初始化段 strcc r2, r3, #4 bcc f2 # 跳转到 main() .extern main ldr r0, =main mov lr, pc bx r0 2.3 移植 c/os- 为了移植c/os-,需要完成一些与处理器相关的数据类型定义、宏定义以及函数 定义15-17。移植的具体项目如表 2.1 所列18,其中钩子函数可以不移植。 下面分析c/os- v2.52 移植到 s3cev40 开发板上的过程: 2.3.1 cpu相关数据类型的定义 因为不同的处理器有不同的字长, 所以c/os-的移植包括了一系列的数据类型定 义,以确保其可移植性。尤其是,c/os-代码从不使用 c 语言中的 short,int 及 long 基于 s3c44b0x 的c/os-的研究与实现 12 表 2.1 移植工作项目 名称 类型 所在文件 语言说明 boolean 数据类型os_cpu.h c int8u 数据类型os_cpu.h c int8s 数据类型os_cpu.h c int16u 数据类型os_cpu.h c int16s 数据类型os_cpu.h c int32u 数据类型os_cpu.h c int32s 数据类型os_cpu.h c fp32 数据类型os_cpu.h c fp64 数据类型os_cpu.h c os_stk 数据类型os_cpu.h c 堆栈类型定义 os_cpu_sr 数据类型os_cpu.h c cpu 状态寄存器类型义 os_critical_method 宏定义 os_cpu.h c 临界区保护实现方法记 os_stk_growth 宏定义 os_cpu.h c 堆栈增长方向 os_enter_critical 宏函数 os_cpu.h c 进入临界区 os_exit_critical 宏函数 os_cpu.h c 退出临界区 osstarthighrdy 函数 os_cpu_s.s汇编启动任务 osctxsw 函数 os_cpu_s.s汇编任务切换 osintctxsw 函数 os_cpu_s.s汇编中断退出时任务换 ostickisr 函数 os_cpu_s.cc 系统时钟中断服务 ostaskstkinit 函数 os_cpu_s.cc 任务堆栈初始化 一些钩子函数 中南民族大学硕士学位论文 13 等数据类型,因为它们是与 cpu 相关的,是不可移植的。下面是 os_cpu.h 文件中定 义的一些基本数据类型和堆栈入口宽度 os_stk。如下所示: typedef unsigned char boolean; typedef unsigned char int8u; typedef signed char int8s; typedef unsigned short int16u; typedef signed short int16s; typedef unsigned long int32u; typedef signed long int32s; typedef float fp32; typedef double fp64; typedef unsigned int os_stk; /* 堆栈入口宽度 */ 2.3.2 os_stk_growth定义 os_stk_growth 在 os_cpu.h 中定义,用来指定堆栈的生长方式。置 os_stk_growth 为 0 表示堆栈从下往上长。置 os_stk_growth 为 1 表示堆栈从 上往下长。这里 os_stk_growth 设为 1。如下所示: #define os_stk_growth 1 2.3.3 os_enter_critical()和 os_exit_critical()函数的编写 同其他内核一样,c/os-为了处理临界段代码,必须关中断,处理完毕后,再开 中断。关中断使得c/os-能够避免其他任务或中断服务例程进入临界段代码。这是由 成对出现的宏 os_enter_critical()和 os_exit_critical()完成的。见程序清单 2.4。 程序清单 2.4 os_enter_critical()和 os_exit_critical() /os_cpu.h 文件 #define os_enter_critical() armdisableint() #define os_exit_critical() armenableint() #os_cpu_a.s 文件 基于 s3c44b0x 的c/os-的研究与实现 14 #void disableint(void) #void enableint(void) .global armdisableint armdisableint: stmdb sp!, r0,lr mrs r0, cpsr orr r0, r0, #noint 禁止中断 msr cpsr_cxsf, r0 ldmia sp!, r0,pc .global armenableint armenableint: stmdb sp!, r0,lr mrs r0, cpsr bic r0, r0, #noint 使能中断 msr cpsr_cxsf, r0 ldmia sp!, r0,pc 2.3.4 os_task_sw()函数的编写 os_task_sw()是一个宏, 它是在c/os-从低优先级任务切换到最高优先级任务 时被调用的。os_task_sw()总是在任务级代码中被调用。任务切换只是简单的将处理 器寄存器保存到将被挂起的任务的堆栈中,并且将更高优先级的任务从堆栈中恢复出 来。 os_task_sw()的实现有两种方法。一种方法是 os_task_sw()模拟中断,且 isr 的向量地址必须指向汇编语言函数 osctxsw(), 在切换任务时, 通过执行 os_task_sw() 来产生中断,中断服务子程序 osctxsw()实现任务切换。另一种方法是直接调用 osctxsw()。这里采用第二种方法。os_task_sw()定义在文件 os_cpu_a.s 中。见程 序清单 2.5。 程序清单 2.5 os_task_sw() #void os_task_sw(void) 中南民族大学硕士学位论文 15 .global os_task_sw os_task_sw: stmfd sp!, lr stmfd sp!, lr stmfd sp!, r0-r12 mrs r4, cpsr stmfd sp!, r4 mrs r4, spsr stmfd sp!, r4 # ospriocur = ospriohighrdy ldr r4, addr_ospriocur ldr r5, addr_ospriohighrdy ldrb r6, r5 strb r6, r4 # 得到当前任务 tcb 地址 ldr r4, addr_ostcbcur ldr r5, r4 str sp, r5 # 得到最高优先级任务 tcb 地址 ldr r6, addr_ostcbhighrdy ldr r6, r6 ldr sp, r6 #ostcbcur = ostcbhighrdy str r6, r4 ldmfd sp!, r4 基于 s3c44b0x 的c/os-的研究与实现 16 msr spsr_cxsf, r4 ldmfd sp!, r4 msr cpsr_cxsf, r4 ldmfd sp!, r0-r12,lr,pc 2.3.5 osstarthighrdy()函数的编写 osstarthighrdy()函数被 osstart()函数调用。osstart()函数负责使就绪状态的任务 开始运行。osstarthighrdy()负责获取新任务的堆栈指针,并从堆栈指针中恢复新任务 的所有寄存器。见程序清单 2.6。 程序清单 2.6 osstarthighrdy() #void osstarthighrdy(void) .global osstarthighrdy osstarthighrdy: bl ostaskswhook mov r0, #1 ldr r1, =osrunning strb r0, r1 ldr r4, addr_ostcbcur ldr r5, addr_ostcbhighrdy ldr r5, r5 ldr sp, r5 str r5, r4 ldmfd sp!, r4 msr spsr_cxsf, r4 ldmfd sp!, r4 msr cpsr_cxsf, r4 ldmfd sp!, r0-r12, lr, pc 中南民族大学硕士学位论文 17 2.3.6 ostaskstkinit()函数的编写 ostaskstkinit()初始化堆栈结构, ostaskcreate()和 ostaskcreatext()函数会调用它。 ostaskstkinit()函数是 os_cpu_c.c 中唯一必要的函数。见程序清单 2.7. 见程序清单 2.7 ostaskstkinit() os_stk *ostaskstkinit (void (*task)(void *pd), void *pdata, os_stk *ptos, int16u opt) unsigned int *stk; opt = opt; stk= (unsigned int *)ptos; /* 初始化新任务堆栈 */ *-stk = (unsigned int) task; /* pc */ *-stk = (unsigned int) task; /* lr */ *-stk = 0; /* r12 */ *-stk = 0; /* r11 */ *-stk = 0; /* r10 */ *-stk = 0; /* r9 */ *-stk = 0; /* r8 */ *-stk = 0; /* r7 */ *-stk = 0; /* r6 */ *-stk = 0; /* r5 */ *-stk = 0; /* r4 */ *-stk = 0; /* r3 */ *-stk = 0; /* r2 */ *-stk = 0; /* r1 */ *-stk = (unsigned int) pdata; /* r0 */ *-stk = (svc32mode|0 x0); /* cpsr irq, fiq 禁止*/ *-stk = (svc32mode|0 x0); /* spsr irq, fiq 禁止 */ 基于 s3c44b0x 的c/os-的研究与实现 18 return (os_stk *)stk; 2.4 测试 c/os-操作系统移植到现在就完成了代码的编写。 下面开始测试操作系统移植代 码的正确性。 测试步骤如下: 1)验证 ostaskstkinit()和 osstarthighrdy()函数; 2)验证 osctxsw()函数; 3)验证时钟节拍函数。 2.4.1 测试步骤(1):验证 ostaskstkinit()和 osstarthighrdy()函数 1)os_cfg.h 中,设置 os_task_stat_en 为 0,禁止统计任务。 2)用 embest ide 的 debug 功能,首先单步进入 osinit()函数,然后单步执行跳入 ostaskstkinit()函数,通过 embest ide 的内存查看器核对任务堆栈初始化数据无误。跳 出 ostaskstkinit()函数后,跳出 osinit()函数。单步进入 osstart()函数。单步执行到 osstart()函数的最后一步 osstarthighrdy()函数。执行这条语句,调试器应该指向 os_taskidle()的第一条指令。观察到调试器在 ostaskidle()函数中循环执行了几次,这 就验证了 osstarthighrdy()函数是成功的。 2.4.2 测试步骤(2):验证 osctxsw()函数 在 main 函数中添加 task1(),task1()仅仅调用延时函数。添加的任务 task1()见程序 清单 2.8。 在等待的时间里, c/os-应该从就绪表中取消当前任务 task1()的任务列表, 而重新调度,在没有其它任务就绪的情况下,切换到空闲任务。观察到在空闲任务中重 复运行了多次,说明任务切换代码编写正确。 程序清单 2.8 验证 osctxsw() void task1(void* pdata) pdata = pdata; 中南民族大学硕士学位论文 19 while(1) ostimedly(90); 2.4.3 测试步骤(3):测试时钟节拍函数 在 main 函数中添加 task2(),task2()中调用延时函数。添加的任务 task2 见程序清 单 2.9。若可以检测到系统的指示灯作循环的闪烁,则说明任务不仅能够从 task2()任务 切换到空闲任务,同时也能在等待时间结束后,从空闲任务切换回当前 task2()任务。这 说明时钟节拍己经正常启动。 程序清单 2.9 验证时钟节拍函数 void task2(void* pdata) pdata = pdata; while(1) ostimedly(90); set_led_on(); ostimedly(100); set_led_off(); 至此,c/os-验证完毕,c/os-移植工作完成。 基于 s3c44b0x 的c/os-的研究与实现 20 第 3 章 优先级数扩充 目前,c/os-最多支持 64 个优先级,因为每个任务的优先级均不同,因此最多 支持 64 个任务。这制约了c/os-应用到较复杂的系统中。有必要对其支持任务数进 行扩展。本章首先分析了c/os-就绪表相关数据结构和算法,然后在此基础上提出了 改进方案并加以实现,最后对改进进行了分析和测试。 3.1 c/os-就绪表 3.1.1 就绪表相关数据结构 在c/os-中,每个任务被赋予不同的优先级等级,从 0 级到最低优先级 os_lowest_pr1o,包括 0 和 os_lowest_pr1o 在内。当c/os-初始化的时候, 最低优先级 os_lowest_pr1o 总是被赋给空闲任务。 为了标志每个任务是否处于就绪态,c/os-引入了两个变量 osrdygrp 和 osrdytbl。 osrdytbl结构如图 3.1 所示8。 当任务进入就绪态时, 就绪表 osrdytbl 中的相应元素的相应位置位。任务按优先级分组,8 个任务为一组。osrdygrp 中的每 一位表示 8 组任务中每一组中是否有进入就绪态的任务。 osrdygrp 和 osrdytbl之间 的关系见图 3.1,是按以下规则给出的: 当 osrdytbl0中的任何一位是 1 时,osrdygrp 的第 0 位置 1; 当 osrdytbl1中的任何一位是 1 时,osrdygrp 的第 1 位置 1; 当 osrdytbl2中的任何一位是 1 时,osrdygrp 的第 2 位置 1; 当 osrdytbl3中的任何一位是 1 时,osrdygrp 的第 3 位置 1; 当 osrdytbl4中的任何一位是 1 时,osrdygrp 的第 4 位置 1; 当 osrdytbl5中的任何一位是 1 时,osrdygrp 的第 5 位置 1; 当 osrdytbl6中的任何一位是 1 时,osrdygrp 的第 6 位置 1; 当 osrdytbl7中的任何一位是 1 时,osrdygrp 的第 7 位置 1。 为了提高就绪表操作的效率,c/os-引入了两个数据结构 osmaptbl和 osunmaptbl。osmaptbl用于计算一个 8 位二进制数某位对应的掩码。见表 3.18。 osunmaptbl用来计算任意一个 8 位二进制数最低位 1 所在的位。 中南民族大学硕士学位论文 21 表 3.1 osmaptbl的值 下标 位掩码 0 00000001 1 00000010 2 00000100 3 00001000 4 00010000 5 00100000 6 01000000 7 10000000 图 3.1 c/os-任务就绪表 osrdygrp osrdytbl ospriohighrdy x y 优先级最低的任务任务的优先级号 优先级最高的任务 在 osrdytbl 中的列数 在 osrdytbl中的行数 和在 osrdygrp 中的位置 基于 s3c44b0x 的c/os-的研究与实现 22 osunmaptbl定义如下19: int8u const osunmaptbl = 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 ; 3.1.2 就绪表相关算法 在c/os-中,任务优先级的低三位用于确定任务在总就绪表 osrdytbl中的所 在位。接下去的三位用于确定是在 osrdytbl数组的第几个元素。见图 3.1。程序清单 3.1 中的代码用于将任务放入就绪表。prio 是任务的优先级。 程序清单 3.1 使任务进入就绪态20 osrdygrp |= osmaptblprio 3; osrdytblprio 3 |= osmaptblprio 程序清单 3.2 中的代码用于将任务从就绪表中删除。 程序清单 3.2 从就绪表中删除一个任务20 if ( (osrdytblprio 3 以上代码将就绪任务表数组 osrdytbl中相应元素的相应位清零,而对于 osrdygrp,只有当被删除任务所在任务组中全组任务一个都没有进入就绪态时,才将 相应位清零。 也就是说 osrdytblprio3所有的位全零时, osrdygrp 的相应位才清零。 为了找到那个进入就绪态的优先级最高的任务,并不需要从 osrdytbl0开始扫描 整个就绪任务表,只需要查另外一张优先级判定表 osunmaptbl256。osrdytbl中每 个字节的 8 位代表这一组的 8 个任务哪些进入就绪态了,低位的优先级高于高位。利用 这个字节为下标来查 osunmaptbl这张表,返回的字节就是该组任务中就绪态任务中 中南民族大学硕士学位论文 23 优先级最高的那个任务所在的位置。这个返回值在 0 到 7 之间。确定进入就绪态的优先 级最高的任务是用以下代码完成的,如程序清单 3.3 所示。 程序清单 3.3 找出进入就绪态的优先级最高的任务20 y = osunmaptblosrdygrp; x = osunmaptblosrdytbly; prio = (y 8 + 8; if ( (osrdytbly 中南民族大学硕士学位论文 25 else ospriohighrdy = (int8u) ( (y 8 + 8); 在程序清单 3.4 中,查找最高优先级任务所在的组是分两步进行的:取 osrdygrp 的低 8 位,如果不全零,则最高优先级任务组在低 8 位对应的任务组中,否则在高 8 位 对应的任务组中。需要注意的是,在高 8 位时,判断表 osunmaptbl所得还要加 8。 在 osrdytbly中查找最高优先级任务同理。 3.4 效率分析 分析以上数据结构和函数的更改,可以看出: 1)从时间上,更改的代码只是增加了求与、判断、移位、求和操作,但时间复杂 度仍是 o(1); 2)从空间上,osrdygrp、oseventgrp、osrdytbl和 oseventtbl等变量的类型 从 int8u 扩充到 int16u,osrdytbl和 oseventtbl数组从最大 8 个元素到最大 16 个元素,内存的增加也很有限。 因此,通过这样的更改,不会对c/os-的性能造成影响。而且,改进的代码执行 时间也是可预测的。保持了c/os-执行时间的确定性。 3.5 测试 可以看出, 虽然需要更改多个函数, 但是修改之处基本上是查找最高优先级的代码。 测试也主要是围绕这部分代码进行的。 在main()函数中建立两个任务, 它们的优先级分别为5和136。 5对应于osrdytbl0 的第 5 位,136 对应于 osrdytbl8的第 8 位。这两个任务的代码都是一样的。如程序 清单 3.5 所示。ostimedly()函数使得任务挂起,所以两个任务按照优先级依次执行。通 过 uart_printf()函数输出任务优先级。实验中观察到 5 和 136 两个优先级轮流显示。这 说明修改后的代码能调度高 8 位组中的高 8 位任务, 从而验证修改后的查找最高优先级 的代码是正确的。 程序清单 3.5 测试代码 void task1(void* pdata) 基于 s3c44b0x 的c/os-的研究与实现 26 pdata = pdata; while(1) uart_printf(current prio = %dn, ospriocur); ostimedly(500); 中南民族大学硕士学位论文 27 第 4 章 轮转调度策略的引入 在嵌入式应用中,为了确保任务的实时性,通常采用优先级调度的策略。c/os- 就是一个基于优先级的抢占式内核。c/os-内核具有高效简洁的特点,但是,它不 支持同优先级的调度。实际应用系统中,比如网络服务系统和数据采集系统,其中某些 任务没有优先级上的高低之分,在这种情况下平均为它们分配 cpu 时间更加合理24,25。 因此有必要在c/os-基于优先级调度的基础上,引入轮转调度策略。 4.1 c/os-任务调度原理 图 4.1 是c/os-的任务状态转换图8。任务可以运行在以下五种状态之下26-28: 1)睡眠态:睡眠态指任务驻留在程序空间之中,还没有交给c/os-管理。把任 务交给c/os-是通过调用下述两个函数之一:ostaskcreate()或 ostaskcreateext()。 当任务一旦建立,这个任务就进入就绪态准备运行。任务的建立可以是在多任务运行开 始之前,也可以是动态地被一个运行着的任务建立。如果一个任务是被另一个任务建立 的,而这个任务的优先级高于建立它的那个任务,则这个刚刚建立的任务将立即得到 cpu 的控制权。一个任务可以通过调用 ostaskdel()返回到睡眠态,或通过调用该函数 让另一个任务进入睡眠态。 2)就绪态:任务一旦建立就进入就绪态。处于等待状态的任务在等待事件发生或 延时时间到时将转入就绪态。 3)运行态:调用 osstart()函数可以启动多任务,它运行用户初始化代码中已经建 立的、进入就绪态的最高优先级任务。当有更高优先级就绪任务时,它将获得 cpu 使 用权而进入运行态。 4)等待态:正在运行的任务因为延时或等待某事件发生而转入等待态。延时可以 通过调用 ostimedly()或 ostimedlyhmsm()函数。等待的时间过去以后,系统服务函 数ostimetick()使延迟了的任务进入就绪态。 任务可以调用ossempend()、 osmboxpend() 或 osqpend()函数等待事件发生,这时任务进入等待态。当等待事件发生时,被挂起的 任务进入就绪态。事件发生的报告可能来自另一个任务,也可能来自中断服务子程序。 5)中断态:当中断发生时,正在运行的任务就转入中断态。中断服务子程序可能 会报告一个或多个事件的发生,而使一个或多个任务进入就绪态。在这种情况下,从中 基于 s3c44b0x 的c/os-的研究与实现 28 断服务子程序返回之前, c/os-要判定被中断的任务是否还是就绪态任务中优先级最 高的。如果中断服务子程序使一个优先级更高的任务进入了就绪态,则新进入就绪态的 这个优先级更高的任务将得以运行,否则原来被中断了的任务才能继续运行。 图 4.1 任务的状态 4.2 轮转调度策略的引入 在分时系统中,每个就绪任务按照就绪时间排成一个 fifo(先进先出)队列29。 每个任务按照队列的顺序获得 cpu 占有权。每个任务被分配一个时间片。当时间片被 使用完时,这个任务就进入等待状态,处于就绪队列头部的任务获得了 cpu 占有权。 这样循环下去。在分时系统里,时间片都是很短的。因此,好像每个任务单独占用 cpu 一样。 c/os-是一个为嵌入式

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论