ImageVerifierCode 换一换
格式:DOC , 页数:32 ,大小:134.50KB ,
资源ID:2169291      下载积分:30 文钱
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,省得不是一点点
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.wenke99.com/d-2169291.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: QQ登录   微博登录 

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文([信息与通信]uCOS-II在51单片机上的移植.doc)为本站会员(龙***)主动上传,文客久久仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知文客久久(发送邮件至hr@wenke99.com或直接QQ联系客服),我们立即给予删除!

[信息与通信]uCOS-II在51单片机上的移植.doc

1、 引言:随着各种应用电子系统的复杂化和系统实时性需求的提高,并伴随应用软件朝着系统化方向发展的加速,在 16 位/32 位单片机中广泛使用了嵌入式实时操作系统。然而实际使用中却存在着大量 8 位单片机,从经济性考虑,对某些应用场合,在 8 位 MCU上使用操作系统是可行的。从学习操作系统角度,uC/OS- II for 51 即简单又全面,学习成本低廉,值得推广。结语:C/OS-II 具有免费、简单、可靠性高、实时性好等优点,但也有缺乏便利开发环境等缺点,尤其不像商用嵌入式系统那样得到广泛使用和持续的研究更新。但开放性又使得开发人员可以自行裁减和添加所需的功能,在许多应用领域发挥着独特的作用。

2、当然,是否在单片机系统中嵌入 C/OS-II 应视所开发的项目而定,对于一些简单的、低成本的项目来说,就没必要使用嵌入式操作系统了。uC/OS-II 原理:uCOSII 包括任务调度、时间管理、内存管理、资源管理(信号量、邮箱、消息队列)四大部分,没有文件系统、网络接口、输入输出界面。它的移植只与 4 个文件相关:汇编文件(OS_CPU_A.ASM)、处理器相关 C 文件(OS_CPU.H 、OS_CPU_C.C )和配置文件(OS_CFG.H )。有 64 个优先级,系统占用 8 个,用户可创建 56 个任务,不支持时间片轮转。它的基本思路就是 “近似地每时每刻总是让优先级最高的就绪任务处于

3、运行状态” 。为了保证这一点,它在调用系统 API 函数、中断结束、定时中断结束时总是执行调度算法。原作者通过事先计算好数据,简化了运算量,通过精心设计就绪表结构,使得延时可预知。任务的切换是通过模拟一次中断实现的。uCOSII 工作核心原理是:近似地让最高优先级的就绪任务处于运行状态。操作系统将在下面情况中进行任务调度:调用 API 函数(用户主动调用),中断(系统占用的时间片中断 OsTimeTick(),用户使用的中断)。调度算法书上讲得很清楚,我主要讲一下整体思路。(1) 在调用 API 函数时,有可能引起阻塞,如果系统 API 函数察觉到运行条件不满足,需要切换就调用 OSSched

4、()调度函数,这个过程是系统自动完成的,用户没有参与。OSSched()判断是否切换,如果需要切换,则此函数调用 OS_TASK_SW()。这个函数模拟一次中断(在 51 里没有软中断,我用子程序调用模拟,效果相同),好象程序被中断打断了,其实是 OS 故意制造的假象,目的是为了任务切换。既然是中断,那么返回地址(即紧邻 OS_TASK_SW()的下一条汇编指令的 PC 地址)就被自动压入堆栈,接着在中断程序里保存 CPU 寄存器(PUSHALL)。堆栈结构不是任意的,而是严格按照 uCOSII 规范处理。OS 每次切换都会保存和恢复全部现场信息(POPALL),然后用RETI 回到任务断点继

5、续执行。这个断点就是 OSSched()函数里的紧邻OS_TASK_SW()的下一条汇编指令的 PC 地址。切换的整个过程就是,用户任务程序调用系统 API 函数,API 调用 OSSched(),OSSched()调用软中断OS_TASK_SW()即 OSCtxSw,返回地址(PC 值)压栈,进入 OSCtxSw 中断处理子程序内部。反之,切换程序调用 RETI 返回紧邻 OS_TASK_SW()的下一条汇编指令的PC 地址,进而返回 OSSched()下一句,再返回 API 下一句,即用户程序断点。因此,如果任务从运行到就绪再到运行,它是从调度前的断点处运行。(2)中断会引发条件变化,在退

6、出前必须进行任务调度。 uCOSII 要求中断的堆栈结构符合规范,以便正确协调中断退出和任务切换。前面已经说到任务切换实际是模拟一次中断事件,而在真正的中断里省去了模拟 (本身就是中断嘛)。只要规定中断堆栈结构和 uCOSII 模拟的堆栈结构一样,就能保证在中断里进行正确的切换。任务切换发生在中断退出前,此时还没有返回中断断点。仔细观察中断程序和切换程序最后两句,它们是一模一样的,POPALL+RETI。即要么直接从中断程序退出,返回断点;要么先保存现场到 TCB,等到恢复现场时再从切换函数返回原来的中断断点(由于中断和切换函数遵循共同的堆栈结构,所以退出操作相同,效果也相同)。用户编写的中断

7、子程序必须按照 uCOSII规范书写。任务调度发生在中断退出前,是非常及时的,不会等到下一时间片才处理。OSIntCtxSw()函数对堆栈指针做了简单调整,以保证所有挂起任务的栈结构看起来是一样的。(3)在 uCOSII 里,任务必须写成两种形式之一(uCOSII 中文版p99 页)。在有些 RTOS 开发环境里没有要求显式调用 OSTaskDel(),这是因为开发环境自动做了处理,实际原理都是一样的。uCOSII 的开发依赖于编译器,目前没有专用开发环境,所以出现这些不便之处是可以理解的。移植过程:(1)拷贝书后附赠光盘 sourcecode 目录下的内容到 C:YY 下,删除不必要的文件和

8、 EX1L.C,只剩下 p187(uCOSII )上列出的文件。(2)改写最简单的 OS_CPU.H数据类型的设定见 C51.PDF 第 176 页。注意 BOOLEAN 要定义成 unsigned char 类型,因为 bit 类型为 C51 特有,不能用在结构体里。EA=0 关中断;EA=1 开中断。这样定义即减少了程序行数,又避免了退出临界区后关中断造成的死机。MCS-51 堆栈从下往上增长(1=向下,0= 向上),OS_STK_GROWTH 定义为 0#define OS_TASK_SW() OSCtxSw() 因为 MCS-51 没有软中断指令,所以用程序调用代替。两者的堆栈格式相同

9、,RETI 指令复位中断系统,RET 则没有。实践表明,对于 MCS-51,用子程序调用入栈,用中断返回指令 RETI 出栈是没有问题的,反之中断入栈 RET 出栈则不行。总之,对于入栈,子程序调用与中断调用效果是一样的,可以混用。在没有中断发生的情况下复位中断系统也不会影响系统正常运行。详见uC/OS-II第八章 193 页第 12 行(3)改写 OS_CPU_C.C我设计的堆栈结构如下图所示:TCB 结构体中 OSTCBStkPtr 总是指向用户堆栈最低地址,该地址空间内存放用户堆栈长度,其上空间存放系统堆栈映像,即:用户堆栈空间大小=系统堆栈空间大小+1。SP 总是先加 1 再存数据,因

10、此,SP 初始时指向系统堆栈起始地址(OSStack)减 1处(OSStkStart)。很明显系统堆栈存储空间大小=SP-OSStkStart 。任务切换时,先保存当前任务堆栈内容。方法是:用 SP-OSStkStart 得出保存字节数,将其写入用户堆栈最低地址内,以用户堆栈最低地址为起址,以 OSStkStart 为系统堆栈起址,由系统栈向用户栈拷贝数据,循环 SP-OSStkStart 次,每次拷贝前先将各自栈指针增 1。其次,恢复最高优先级任务系统堆栈。方法是:获得最高优先级任务用户堆栈最低地址,从中取出“长度”,以最高优先级任务用户堆栈最低地址为起址,以 OSStkStart 为系统堆

11、栈起址,由用户栈向系统栈拷贝数据,循环“长度” 数值指示的次数,每次拷贝前先将各自栈指针增 1。用户堆栈初始化时从下向上依次保存:用户堆栈长度(15),PCL,PCH,PSW,ACC,B,DPL,DPH,R0,R1,R2 ,R3,R4,R5,R6,R7。不保存 SP,任务切换时根据用户堆栈长度计算得出。OSTaskStkInit 函数总是返回用户栈最低地址。操作系统 tick 时钟我使用了 51 单片机的 T0 定时器,它的初始化代码用 C 写在了本文件中。最后还有几点必须注意的事项。本来原则上我们不用修改与处理器无关的代码,但是由于 KEIL 编译器的特殊性,这些代码仍要多处改动。因为 KE

12、IL 缺省情况下编译的代码不可重入,而多任务系统要求并发操作导致重入,所以要在每个 C 函数及其声明后标注reentrant 关键字。另外,“pdata”、 “data”在 uCOS 中用做一些函数的形参,但它同时又是 KEIL 的关键字,会导致编译错误,我通过把“pdata”改成 “ppdata”, “data”改成“ddata”解决了此问题。OSTCBCur、OSTCBHighRdy、OSRunning、OSPrioCur、 OSPrioHighRdy 这几个变量在汇编程序中用到了,为了使用 Ri 访问而不用 DPTR,应该用 KEIL 扩展关键字 IDATA 将它们定义在内部 RAM 中

13、。(4)重写 OS_CPU_A.ASMA51 宏汇编的大致结构如下:NAME 模块名 ;与文件名无关;定义重定位段 必须按照 C51 格式定义,汇编遵守 C51 规范。段名格式为:?PR?函数名?模块名;声明引用全局变量和外部子程序 注意关键字为“EXTRN”没有E全局变量名直接引用无参数/无寄存器参数函数 FUNC带寄存器参数函数 _FUNC重入函数 _?FUNC;分配堆栈空间只关心大小,堆栈起点由 keil 决定,通过标号可以获得 keil 分配的 SP 起点。切莫自己分配堆栈起点,只要用 DS 通知 KEIL 预留堆栈空间即可。?STACK 段名与 STARTUP.A51 中的段名相同,

14、这意味着 KEIL 在 LINK 时将把两个同名段拼在一起,我预留了 40H 个字节,STARTUP.A51 预留了 1 个字节,LINK 完成后堆栈段总长为 41H。查看 yy.m51 知 KEIL 将堆栈起点定在 21H,长度 41H,处于内部RAM 中。;定义宏宏名 MACRO 实体 ENDM;子程序OSStartHighRdyOSCtxSwOSIntCtxSwOSTickISRSerialISREND ;声明汇编源文件结束一般指针占 3 字节。+0 类型+1 高 8 位数据+2 低 8 位数据 详见 C51.PDF 第 178 页低位地址存高 8 位值,高位地址存低 8 位值。例如 0

15、x1234,基址+0:0x12 基址+1:0x34(5)移植串口驱动程序在此之前我写过基于中断的串口驱动程序,包括打印字节/字/ 长字/字符串,读串口,初始化串口/缓冲区。把它改成重入函数即可直接使用。系统提供的显示函数是并发的,它不是直接显示到串口,而是先输出到显存,用户不必担心 IO 慢速操作影响程序运行。串口输入也采用了同样的技术,他使得用户在 CPU 忙于处理其他任务时照样可以盲打输入命令。(6)编写测试程序 Demo(YY.C)Demo 程序创建了 3 个任务 A、B 、C 优先级分别为 2、3、4,A 每秒显示一次,B 每3 秒显示一次,C 每 6 秒显示一次。从显示结果看,显示

16、3 个 A 后显示 1 个 B,显示 6 个A 和 2 个 B 后显示 1 个 C,结果显然正确。显示结果如下:AAAAAA111111 is activeAAAAAA111111 is activeAAAAAA111111 is activeBBBBBB333333 is activeAAAAAA111111 is activeAAAAAA111111 is activeAAAAAA111111 is activeBBBBBB333333 is activeCCCCCC666666 is activeAAAAAA111111 is activeAAAAAA111111 is activeAA

17、AAAA111111 is activeBBBBBB333333 is activeAAAAAA111111 is activeAAAAAA111111 is activeAAAAAA111111 is activeBBBBBB333333 is activeCCCCCC666666 is activeDemo 程序经 Keil701 编译后,代码量为 7-8K,可直接在 KeilC51 上仿真运行。编译时要将 OS_CPU_C.C、UCOS_II.C、OS_CPU_A.ASM、YY.C 加入项目文件名 : OS_CPU_A.ASM$NOMOD51EA BIT 0A8H.7SP DATA 08

18、1HB DATA 0F0HACC DATA 0E0HDPH DATA 083HDPL DATA 082HPSW DATA 0D0HTR0 BIT 088H.4TH0 DATA 08CHTL0 DATA 08AHNAME OS_CPU_A ;模块名;定义重定位段?PR?OSStartHighRdy?OS_CPU_A SEGMENT CODE?PR?OSCtxSw?OS_CPU_A SEGMENT CODE?PR?OSIntCtxSw?OS_CPU_A SEGMENT CODE?PR?OSTickISR?OS_CPU_A SEGMENT CODE?PR?_? serial?OS_CPU_A SEG

19、MENT CODE;声明引用全局变量和外部子程序EXTRN IDATA (OSTCBCur)EXTRN IDATA (OSTCBHighRdy)EXTRN IDATA (OSRunning )EXTRN IDATA (OSPrioCur)EXTRN IDATA (OSPrioHighRdy)EXTRN CODE (_?OSTaskSwHook)EXTRN CODE (_?serial)EXTRN CODE (_?OSIntEnter)EXTRN CODE (_?OSIntExit )EXTRN CODE (_?OSTimeTick);对外声明 4 个不可重入函数PUBLIC OSStartHi

20、ghRdyPUBLIC OSCtxSwPUBLIC OSIntCtxSwPUBLIC OSTickISR;PUBLIC SerialISR ;分配堆栈空间。只关心大小,堆栈起点由 keil 决定,通过标号可以获得 keil 分配的 SP 起点。?STACK SEGMENT IDATARSEG ?STACKOSStack:DS 40HOSStkStart IDATA OSStack-1;定义压栈出栈宏PUSHALL MACROPUSH PSWPUSH ACCPUSH BPUSH DPLPUSH DPHMOV A, R0 ;R0-R7 入栈PUSH ACCMOV A, R1PUSH ACCMOV

21、A, R2PUSH ACCMOV A, R3PUSH ACCMOV A, R4PUSH ACCMOV A, R5PUSH ACCMOV A, R6PUSH ACCMOV A, R7PUSH ACC;PUSH SP ;不必保存 SP,任务切换时由相应程序调整ENDMPOPALL MACRO;POP ACC ;不必保存 SP,任务切换时由相应程序调整POP ACC ;R0-R7 出栈MOV R7,APOP ACCMOV R6,APOP ACCMOV R5,APOP ACCMOV R4,APOP ACCMOV R3,APOP ACCMOV R2,APOP ACCMOV R1,APOP ACCMOV

22、R0,APOP DPHPOP DPLPOP BPOP ACCPOP PSWENDM;子程序;-RSEG ?PR?OSStartHighRdy?OS_CPU_AOSStartHighRdy:USING 0 ;上电后 51 自动关中断,此处不必用 CLR EA 指令,因为到此处还未开中断,本程序退出后,开中断。LCALL _?OSTaskSwHookOSCtxSw_in:;OSTCBCur = DPTR 获得当前 TCB 指针,详见 C51.PDF 第 178 页MOV R0,#LOW (OSTCBCur) ;获得 OSTCBCur 指针低地址,指针占 3 字节。+0 类型+1 高 8 位数据+2 低 8 位数据INC R0MOV DPH,R0 ;全局变量 OSTCBCur 在 IDATA 中INC R0MOV DPL,R0;OSTCBCur-OSTCBStkPtr = DPTR 获得用户堆栈指针INC DPTR ;指针占 3 字节。+0 类型+1 高 8 位数据+2 低 8 位数据MOVX A,DPTR ;.OSTCBStkPtr 是 void 指针MOV R0,A

Copyright © 2018-2021 Wenke99.com All rights reserved

工信部备案号浙ICP备20026746号-2  

公安局备案号:浙公网安备33038302330469号

本站为C2C交文档易平台,即用户上传的文档直接卖给下载用户,本站只是网络服务中间平台,所有原创文档下载所得归上传人所有,若您发现上传作品侵犯了您的权利,请立刻联系网站客服并提供证据,平台将在3个工作日内予以改正。