uCOS移植心得Word下载.docx
《uCOS移植心得Word下载.docx》由会员分享,可在线阅读,更多相关《uCOS移植心得Word下载.docx(17页珍藏版)》请在冰点文库上搜索。
![uCOS移植心得Word下载.docx](https://file1.bingdoc.com/fileroot1/2023-4/29/deffe2a8-d892-42b1-b5cc-ae29af1ac79f/deffe2a8-d892-42b1-b5cc-ae29af1ac79f1.gif)
中断。
前/后台系统中还有一种驱动事件的产生,在主循环中不断的查询。
有别与一般的定时查
询,这种查询是为了将事件的响应时间降到最低,也可以将其归纳于定时(时间)事件。
(2)uCOSC51移植的准备工作;
2004年8月份,我在书城买了一本《uCOS-Ⅱ第2版》,准备学习RTOS。
因为以前没有玩过
RTOS,在工作之余断断续续的看了3、4章。
一直到12月初的时候,公司要重新设计一个项
目,恰好要把uCOS移植到c51上。
我的RTOS学习才正式开始。
因为对OS向往以久,我并不想在网上Down一个现成的移植OS程序,做一个OS的应用者。
揭开
OS的神秘面纱,了解OS的内部运行机制,这才是我想要做的。
本文的主要目的是讨论uCOS的
移植,希望对即将进行uCOSc51移植的兄弟有些帮助。
对于OS的内部运行机制,由于东西比
较多,在这里不想太展开。
如果以后有时间,也想写一篇文章来讨论讨论。
最开始,我的计划就是看书,看《uCOS-Ⅱ第2版》。
看完这本几百页的大本本,花了我2个
半星期。
因为是工作需要,我才可以这样心安理得的在那里看呀看书^_^,辛苦呀9。
在这期
间,为了自己的思想不受别人的影响,我坚决没有从网上下任何uCOS的资料,我手头的资料
就是uCOS-Ⅱ的书和附带光盘,这些就是最权威的资料了。
在看书的时候,我都坚持做笔
记,把每天的重点,明白的东西和心中的疑问都随时记录下来。
对付这种大本本,前后的知
识又相互关联,光靠我们的大脑是搞不定啊。
弄懂了uCOS的内核,下一本书应该是《单片机高级语言C51Windows环境编程与应用》。
对于
KeilC我还是很熟的,还是花了2、3天来复习。
这里的重点是C51对汇编的转换结构,例于
数据/系统堆栈的使用,C&
Asm混合编程。
我想对于任何CPU的uCOS移植,C语言的实现机制,
你都是要了解的。
这里也是要花大把时间的。
《uCOS-Ⅱ第2版》和《单片机高级语言C51Windows环境编程与应用》这两本书网上都可以
下电子档的,我这里也有(大家需要可以来信索取)。
uCOS和C51的书都看完了。
我就下载了一堆uCOS的C51移植资料。
其中的源程序有很多个版本
的,不过详细的移植文档只有一个版本:
巨龙一位大虾的"
uCOSC51移植心得"
,相信很多人
都看过。
这些资料的作者都是我移植过程中的老师,有了这些资料,我才能把心中的朦胧想
法变成源程序。
但是我也发现这些资料中大多都有一些错误和遗漏,当然这是难免的。
这也
正是驱使我写这篇文章的原因,希望在前辈的基础上有所进步。
欢迎大家来批评!
真正的源代码移植,我花了大概一个星期时间。
(3)uCOSC51的移植概况;
1、工具:
uCOS2.52版;
KeilCV6.23a。
2、uCOSV2.52的文件结构与移植所需要的修改:
A、与处理器无关的文件:
OS_CORE.C
OS_FLAG.C
OS_MBOX.C
OS_MEM.C
OS_MUTEX.C
OS_Q.C
OS_SEM.C
OS_TASK.C
OS_TIME.C
uCOS_II.C
uCOS_II.H
这些文件在c51的移植过程中,只需要给函数加上重入属性即可。
B、与应用相关的文件:
INCLUDES.H:
包含C51的标准库头文件;
对"
pdata"
等c51关键字的重定义
OS_CFG.H:
"
OS_TICKS_PER_SEC"
、"
OS_FLAGS"
注意可能需要修改。
C、与处理器相关的文件:
OS_CPU.H:
数据类型、关中断方法、任务堆栈方向、任务切换的宏定义都需要修改。
OS_CPU_A.ASM:
OSTickISR()、OSStartHighRdy()、OSCtxSw()、OSIntCtxSw()这几个函数
的编写,是整个移植的关键。
OS_CPU_C.C:
OSTaskStkInit()函数的编写。
(4)uCOSC51具体的移植过程;
1、C51的堆栈结构;
这是整个移植过程中的重中之重,所以特别详细介绍。
A、系统堆栈;
c51中,系统堆栈的栈底地址是"
?
STACK"
,栈顶指针就是"
SP"
拉,栈的生长方向是向上的,
栈空间分配在51的内部RAM(idata)中。
"
分配在所有内部RAM数据段的最后面,所
以系统堆栈的范围是从?
STACK到内部RAM的最高位(0x80或者0xFF)。
B、数据堆栈;
c51中,由于我们使用OS,采用的LARGE编译模式,所以数据堆栈的指针是"
C_XBP"
,栈的生
长方向是向下的,栈空间分配在51的外部RAM(xdata)中。
C、C51中断中堆栈的保护;
研究中断中堆栈的保护的意义在于,因为uCOS中的任务切换,本身就是模拟一次中断的发
生:
保护Task1的CPU寄存器,SP切换到Task2的堆栈,弹出Task2的CPU寄存器。
用C51写中断
函数的时候,编译器会自动保护CPU的寄存器,所以中断返回时任务调度OSIntCtxSw(),就
不用重新保护寄存器。
C51中断中调用函数可以分为四种情况(中断函数本身不设为reentrant):
一、
没有函数调用;
二、
调用非reentrant函数,函数中没有嵌套调用其他函数;
三、
调用非reentrant函数,函数中嵌套调用其他函数;
四、
调用reentrant函数。
t0_isr:
PUSH
ACC
B
DPH
DPL
PSW
MOV
PSW,#00H
AR0
AR1
AR2
AR3
AR4
AR5
AR6
AR7
用户代码
POP
AR7
AR6
AR5
AR4
AR3
AR2
AR1
AR0
PSW
DPL
DPH
B
ACC
RETI
因为uCOS中所有的函数都必须是重入函数,因此我们只需要研究第四种情况下的堆栈保护,
对于其他情况有兴趣可以在c51中看看。
(注意:
可能因为c51编译器的版本不同,上述压栈
的顺序可能不同。
)
2、uCOSC51任务切换时的堆栈操作;
每个任务都有一个独立的数据堆栈,系统堆栈是公用空间。
保护Task1的CPU寄存器:
首先将CPU寄存器按上例压进Task1系统堆栈,再将整个Task1系统
堆栈压进Task1数据堆栈;
SP切换:
C_XBP=Task2的数据堆栈栈顶地址。
弹出Task2的CPU寄存器:
从Task2的数据堆栈重新恢复整个系统堆栈,然后再从Task2系统堆
栈中恢复CPU寄存器值。
实现的方法有很多种,只要遵循uCOS任务切换的原理就可以了。
3、INCLUDES.H的移植;
重点:
是C51关键字,所以要重新定义
源代码:
#include
#defineTASK_REENTRANT
largereentrant
#defineKCREENTRANT
largereentrant
os_cpu.h"
os_cfg.h"
#definedata
ucos51_data
#defineidata
ucos51_idata
#definepdata
ucos51_pdata
#definexdata
ucos51_xdata
ucos_ii.h"
4、OS_CPU.H的移植;
typedefunsignedchar
BOOLEAN;
INT8U;
typedefsigned
char
INT8S;
typedefunsignedint
INT16U;
int
INT16S;
typedefunsignedlong
INT32U;
long
INT32S;
typedeffloat
FP32;
OS_STK;
#defineBYTE
INT8S
#defineUBYTE
INT8U
#defineWORD
INT16S
#defineUWORD
INT16U
#defineLONG
INT32S
#defineULONG
INT32U
C51编程:
uCOS51移植心得
asdjf@
2002/10/03
前一段时间,我参与了一个SNMP网管板的项目,我负责硬件设计和单板软件开发。
该板的硬
件由MCS51+RTL8019AS组成,有64K
FLASH
和64K
SRAM。
软件部分有操作系统和TCPIP协议栈。
硬件比较简单,用了一个月就搞定了,协议栈我参考了老古开发板的部分程序又上网找了SNMP源
代码也很快完成了,但是测试时发现当使用较低时钟频率的CPU时(为了降低成本),由于ASN.1
编解码部分过于庞大,而我的程序又是一个大循环,AGENT的响应速度受到严重影响,用户界面也
反应迟钝。
更坏的消息是公司为了适应市场需求,还要在上面跑PPP和
<
a
href=HTTP
target=_blank>
HTTP
/a>
。
那样的话,我就得
用40MHz的AT89C51RD2或者人为的把程序断成几部分然后用状态机的方法在运行时再把它们连接
起来。
不过,我不想增加成本,也不想把程序搞乱,迫不得已,只好使用操作系统。
说实在的,一开始我也不是很有把握,一来我不清楚51的FLASH是否装得下这么多代码,二
来我只做过OS应用开发,对于它的移植想都不敢想。
不过,我在BBS上搜索了一阵儿后还是有了一
些头绪。
我找到了几个OS的源代码(我喜欢用现成的),按照代码大小、实时性、使用人数、众
人口碑等标准,最后选定了uCOS2。
我感觉它的实时性有保障,延时可预测,代码据说可小到
2K,网上讨论这个话题的人也比较多,而且它的网站上有针对KEIL
C51的移植实例。
经过一番查找,我得到了5个版本。
其中3个是用KEIL编译的。
本来我想直接把OS代码嵌到应
用程序中,但后来发现没有一个可以直接使用。
有的无法用KEIL直接编译,有的需要修改DLL在
软件仿真下使用。
而我需要的是能在串口输入输出,不需要修改任何无关软件,能在软件仿真和
硬件上运行的实时多任务操作系统。
没有办法,我只好硬着头皮去改编。
我分析了自己的劣势:
1。
KEIL刚开始使用,不太熟悉;
2。
混合编程以前从没有作过;
3。
时间紧迫,要在1个月内搞定。
而我的优势就是有5个移植实例可供参考,可以上网查资料。
一开
始,我用“堆栈”、“混合编程”、“汇编”、“ucos”等关键字在C51BBS和老古论坛上检索相
关信息并逐条阅读,读过之后,头脑中的思路逐渐清晰了。
我了解到在KEIL的HLP目录下有
A51.PDF和C51.PDF非常全面的介绍了汇编和C51,是KEIL的权威用户手册;
SP初始化、内存清0
等操作在STARTUP.A51文件中实现,用户可以改写它;
KEIL的变量,子程序等的分配信息可以
在.M51文件里查到;
KEIL自己的论坛里有很多疑难问题的解答……通过阅读并经过思考,解决了
堆栈起点、堆栈空间大小的设定等关键问题。
论坛里的问题有些是我没有想到的,这使我发现了
自己的疏漏。
在网上获得大量信息后,我开始阅读《uCOSII》中文版,一共读了3遍。
第一遍是浏览,了
解到uCOSII包括任务调度、时间管理、内存管理、资源管理(信号量、邮箱、消息队列)四大部
分,没有文件系统、网络接口、输入输出界面。
它的移植只与4个文件相关:
汇编文件
(OS_CPU_A.ASM)、处理器相关C文件(OS_CPU.H、OS_CPU_C.C)和配置文件(OS_CFG.H)。
有64个优先级,系统占用8个,用户可创建56个任务,不支持时间片轮转。
第二遍主要是把整个工
作过程在头脑里过了一下,不懂地方有针对性的查书,重点是思考工作原理和流程。
我发现其实
它的思路挺简单的。
就是
“近似地每时每刻总是让优先级最高的任务处于运行状态”
为了保
证这一点,它在调用系统API函数、中断结束、定时中断结束时总是执行调度算法。
原作者通过事
先计算好数据,简化了运算量,通过精心设计就绪表结构,使得延时可预知。
任务的切换是通过
模拟一次中断实现的。
第三遍重点看了移植部分的内容。
对照实例,研究了代码的具体实现方
法。
前期准备用了20几天,真正编写代码只用了1.5天,调试用了2天。
具体过程如下:
(1)拷贝书后附赠光盘sourcecode目录下的内容到C:
\YY下,删除不必要的文件和EX1L.C,
只剩下p187(《uCOSII》)上列出的文件。
(2)改写最简单的OS_CPU.H
数据类型的设定见C51.PDF第176页。
注意BOOLEAN要定义成unsigned
char
类型,因为
bit类型为C51特有,不能用在结构体里。
EA=0关中断;
EA=1开中断。
这样定义即减少了程序行数,又避免了退出临界区后关中断
造成的死机。
MCU-51堆栈从下往上增长(1=向下,0=向上),OS_STK_GROWTH定义为0
#define
OS_TASK_SW()
OSCtxSw()
因为MCU-51没有软中断指令,所以用程序调用代
替。
两者的堆栈格式相同,RETI指令复位中断系统,RET则没有。
实践表明,对于MCU-51,用子
程序调用入栈,用中断返回指令RETI出栈是没有问题的,反之中断入栈RET出栈则不行。
总之,
对于入栈,子程序调用与中断调用效果是一样的,可以混用。
在没有中断发生的情况下复位中断
系统也不会影响系统正常运行。
详见《uC/OS-II》第八章193页第12行
(3)改写OS_CPU_C.C
我设计的堆栈结构如下图所示:
********************************************************************************
*
*
----------
|OSTCBCur|
|
|
-----------------------
\---->
|OSTCBCur->
OSTCBStkPtr|
SP---->
----------
-
.
|长度
+1
OSStack---->
OSStkStart---->
不关心
-
1
低地址
\-------->
长度
低地址
系统堆栈
用户堆栈
长度=SP-OSStkStart
TCB结构体中OSTCBStkPtr总是指向用户堆栈最低地址,该地址空间内存放用户堆栈长
度,其上空间存放系统堆栈映像,即:
用户堆栈空间大小=系统堆栈空间大小+1。
SP总是先加1再存数据,因此,SP初始时指向系统堆栈起始地址(OSStack)减1处
(OSStkStart)。
很明显系统堆栈存储空间大小=SP-OSStkStart。
任务切换时,先保存当前任务堆栈内容。
方法是:
用SP-OSStkStart得出保存字节数,将
其写入用户堆栈最低地址内,以用户堆栈最低地址为起址,以OSStkStart为系统堆栈起址,由系
统栈向用户栈拷贝数据,循环SP-OSStkStart次,每次拷贝前先将各自栈指针增1。
其次,恢复最高优先级任务系统堆栈。
获得最高优先级任务用户堆栈最低地
址,从中取出“长度”,以最高优先级任务用户堆栈最低地址为起址,以OSStkStart为系统堆栈
起址,由用户栈向系统栈拷贝数据,循环“长度”数值指示的次数,每次拷贝前先将各自栈指针
增1。
用户堆栈初始化时从下向上依次保存:
用户堆栈长度(15),PCL,PCH,PSW,ACC,
B,DPL,DPH,R0,R1,R2,R3,R4,R5,R6,R7。
不保存SP,任务切换时根据用户堆栈长度计
算得出。
OSTaskStkInit函数总是返回用户栈最低地址。
操作系统tick时钟我使用了51单片机的T0定时器,它的初始化代码用C写在了本文件中。
最后还有几点必须注意的事项。
本来原则上我们不用修改与处理器无关的代码,但是由
于KEIL编译器的特殊性,这些代码仍要多处改动。
因为KEIL缺省情况下编译的代码不可重入,而
多任务系统要求并发操作导致重入,所以要在每个C函数及其声明后标注reentrant关键字。
另
外,“pdata”、“data”在uCOS中用做一些函数的形参,但它同时又是KEIL的关键字,会导致
编译错误,我通过把“pdata”改成“ppdata”,“data”改成“ddata”解决了此问题。
OSTCBCur、OSTCBHighRdy、OSRunning、OSPrioCur、OSPrio