您的位置 首页 解答

uC/OS-II在51单片机上的移植2

文件名:YYC#includedefineMAX_STK_SIZE64voidTaskStartyya(void*yydata)reentrant;voidTaskStartyyb(void*yyda

文件名 : YY.C

#i nclude

#define MAX_STK_SIZE 64

void TaskStartyya(void *yydata) reentrant;
void TaskStartyyb(void *yydata) reentrant;
void TaskStartyyc(void *yydata) reentrant;

OS_STK TaskStartStkyya[MAX_STK_SIZE+1];//留意:我在ASM文件中设置?STACK空间为40H即64,不要超出范围。
OS_STK TaskStartStkyyb[MAX_STK_SIZE+1];//用户栈多一个字节存长度
OS_STK TaskStartStkyyc[MAX_STK_SIZE+1];

void main(void)
{
OSInit();

InitTimer0();
InitSerial();
InitSerialBuffer();

OSTaskCreate(TaskStartyya, (void *)0, &TaskStartStkyya[0],2);
OSTaskCreate(TaskStartyyb, (void *)0, &TaskStartStkyyb[0],3);
OSTaskCreate(TaskStartyyc, (void *)0, &TaskStartStkyyc[0],4);

OSStart();
}

void TaskStartyya(void *yydata) reentrant
{
yydata=yydata;
clrscr();
PrintStr(“\n\t\t*******************************\n”);
PrintStr(“\t\t* Hello! The world. *\n”);
PrintStr(“\t\t*******************************\n\n\n”);

for(;;){
PrintStr(“\tAAAAAA111111 is active.\n”);
OSTimeDly(OS_TICKS_PER_SEC);
}
}

void TaskStartyyb(void *yydata) reentrant
{
yydata=yydata;

for(;;){
PrintStr(“\tBBBBBB333333 is active.\n”);
OSTimeDly(3*OS_TICKS_PER_SEC);
}
}

void TaskStartyyc(void *yydata) reentrant
{
yydata=yydata;

for(;;){
PrintStr(“\tCCCCCC666666 is active.\n”);
OSTimeDly(6*OS_TICKS_PER_SEC);
}
}

重入问题的处理:
使命函数中带有形参和局部变量时若运用reentrant关键字会引起重入,从C51.PDF 129-131页的内容知:为了函数重入,形参和局部变量有必要保存在仓库里,因为51硬件仓库太小,KEIL将依据内存形式在相应内存空间仿真仓库(成长方向由上向下,与硬件栈相反)。关于大形式编译,函数回来地址保存在硬件仓库里,形参和局部变量放在仿真仓库中,栈指针为?C_XBP,XBPSTACK=1时,起始值在startup.a51中初始化为FFFFH+1。仿真仓库功率低下,KEIL主张尽量不用,但为了重入操作有必要运用。KEIL能够混合运用3种仿真仓库(大、中、小形式),为了进步功率,针对51引荐一致运用大形式编译。
为了支撑重入,从头规划了仓库结构(如下图)。增加了保存仿真仓库指针?C_XBP和仓库内容的数据结构。相应改动的文件有:OS_CPU_A.ASM、OS_CPU_C.C、OS_CPU.H、YY.C。由图可知,用户栈中保存的仿真栈与硬件栈相向成长,中心为闲暇距离,显着uCOSII的仓库检测函数失效。硬件栈的保存康复详见上节,仿真仓库的保存与8086移植中的相同,OS只提供仓库空间和只操作仓库指针,不进行内存复制,功率相对很高。
主张运用一致的固定巨细的仓库空间,虽然uCOSII原作者把不同使命运用不同空间看成是长处,但为了在51上有用完成使命重入,针对51笔者仍是坚持不运用这个长处。
用户仓库空间的巨细是能够准确计算出来的。用户仓库空间=硬件仓库空间+仿真仓库空间。硬件栈占用内部RAM,内部RAM履行功率高,假如仓库空间过大,会影响KEIL编译的程序功能。假如仓库空间小,在中止嵌套和程序调用时会形成体系溃散。概括考虑,我把硬件仓库空间巨细定成了64字节,用户依据实践状况能够自行设定。仿真仓库巨细取决于形参和局部变量的类型及数量,能够准确算出。因为一切用户栈运用相同空间巨细,所以取占用空间最大的使命函数的空间巨细为仿真仓库空间巨细。这样用户仓库空间巨细就仅有确认了。我将用户仓库空间巨细用宏界说在OS_CFG.H文件中,宏名为MaxStkSize。
51的SP只要8位,无法在64K空间中自在移动,只好选用复制悉数硬件仓库内容的笨办法。51 本来就弱,这么一来缺陷更显着了。其实,引进OS必定要付出代价,一般OS要占用CPU10%-20%的负荷才能,请权衡利弊决议。切换频率决议了CPU的消耗,频率越高消耗越大,大到必定程度就该换更强的CPU了。我选了50Hz的切换频率,不高也不低,用户能够依据需要自行确定。在消耗无法防止的状况下,我采取了几个办法来进步功率:1。ret和reti混用削减代码;2。IE、SP不入出栈,经过其他方法处理;3。用IDATA关键字声明在汇编中用到的全局变量,变DPTR操作为Ri操作;4。规划仓库结构,简化算法;5。让串口输入输出作业在体系态,不占用使命TCB和优先级,增加弹性缓冲区,削减等候。

51单片机上硬件仿真uCOS51的阐明:
zyware网友2002/11/22来信问询uCOS51在单片机上的硬件仿真问题,详细状况是“在51上用uCOS51核,以及一些构件,keilc上仿真经过,用wave接硬件仿真程序乱飞,wave仿真曾经的程序没有问题,不知是何原因”。
因为我的OS程序已经在KEIL软件仿真和硬件上实践测验过,所以不或许是程序错。或许的原因只能是硬件仿真软件设置问题。自己用的是Medwin软件,在Insight上调试,运用uCOS51编译测验程序相同跑飞。即便增加修正后的startup.a51(详见《在51单片机上固化uCOS51的阐明》)也不正常。我发现Medwin好像没有编译startup.a51,因为它把该文件加在了other Files目录下而不是source Files目录,所以我猜想只要放在source Files目录下的文件才被编译。由观察知,以.c和.asm做后缀的文件均被放在此目录下且被编译。所以我立行将startup.a51改成startup.asm并参加项目编译,成果测验正常。不用忧虑startup改名形成抵触,KEIL在链接方针文件时会主动处理重名段,本目录的文件优先级高(我是这么了解的,详细原理不清楚,这仅仅依据实践得到的定论,期望了解此处理进程的朋友能告之,不胜感激。)。

详细做法如下:
1。按《在51单片机上固化uCOS51的阐明》一文修正startup.a51,并将其更名为startup.asm。
2。将startup.asm、yy1.c、os_cpu_c.c、ucos_ii.c、os_cpu_a.asm五个文件参加项目编译。
3。运转

在51单片机上固化uCOS51的阐明:
近来,收到多位网友来信问询uCOS51在51单片机上的固化问题,概括其焦点便是:为什么OS在KeilC51上模仿能够正常运转,但把它烧录在CPU上却不能作业?理论上,程序在软件仿真经过测验后,将其烧录在硬件上,硬件调试应该一次成功。许多网友也有这个经历,可为什么在调试uCOS51时失效了呢?莫非操作体系调试很特别吗?
其实问题出在重入函数的引进。本来KEILC51软件仿真在不修正startup.a51文件的状况下,缺剩运用64K外部RAM,它把0000H-FFFFH悉数仿真为可读写的RAM,而用户的硬件体系或许没有用到那么大的RAM空间,比方只用了8K/16K/32K等,或许用户把一些地址空间映射给了其他设备,比方8019AS等。在没有调用OSTaskCreate前,界说为reentrant的函数将用FFE0H做仿真仓库栈顶指针,而此处在用户的体系里不是RAM,形成程序跑飞。比方在我的用户板上,将FE00H-FFFFH空间的一部分分配给8019AS运用,假如把demo程序编译后直接烧到51上,将不能运转。处理办法是依据体系RAM装备,修正startup.a51文件,并将其参加项目编译,如下所示:

XBPSTACK EQU 1 ; set to 1 if large reentrant is used.
XBPSTACKTOP EQU 07FFFH+1; set top of stack to highest location+1.

按此修正后,在有32K外部RAM的体系上能够正常运转。用户可依据自己XRAM的实践装备状况修正startup.a51相关参数,并将其增加到项目里编译。不用理睬KEIL/C51/LIB目录下的同名文件,此处的startup.a51优先级高,KEIL将按此处该文件的装备编译项目。
这也解说了有些网友问到的,“为什么参加reentrant关键字,在软件仿真时正确,烧在芯片上就死机,去掉reentrant后两者都正常”的问题。因为大多数人很少运用重入函数,往往不了解这个细节,特此提请我们留意。

关于uCOS51不能正常作业的原因还或许是因为串口波特率和OS_TICKS_PER_SEC及TH0、TL0设置不正确引起的。demo程序默许运用22.1184MHz晶体,19200波特率,切换频率为50Hz。为此,1。在SERIAL.C中设置“TL1=0xFD;TH1=0xFD;”使波特率为19200;2。在OS_CPU_C.C和OS_CPU_A.ASM中设置“TH0=0x70;TL0=0x00;”使时钟节拍tick=50次/秒;3。在OS_CFG.H中设置OS_TICKS_PER_SEC为50Hz。用户应依据实践状况,相应地修正这些参数,不然运转不正确。

定时器初值设置:

定时器0用于时钟节拍发生器
/
} wt[MaxLenWordTable];
} WORDTABLE;

取词
bit GetWord(unsigned char *ComBuf,WORDTABLE *WordTable)
{
int i=0;
int j=0;
int k=-1;
int StrFlag=0;
int SentenceEndFlag=0;
char ch;

WordTable->Num=0;
WordTable->LeftCurveNum=0;
WordTable->RightCurveNum=0;

ch=ComBuf[0];
while(!SentenceEndFlag&&i if((ch>=’0’&&ch<=’9’)||(ch>=’a’&&ch<=’z’)||(ch>=’A’&&ch<=’Z’)||(ch==’.’)){
if(StrFlag==0){
StrFlag=1;k=k+1;j=0;
if(k>=MaxLenWordTable) return 0;
WordTable->wt[k].Str[j]=ch;
WordTable->Num=k+1;
}
else{
j=j+1;
if(j>=MaxLenWord) return 0;
WordTable->wt[k].Str[j]=ch;
}
}
else if(ch==’ ’||ch==’,’||ch==’(’||ch==’)’||ch==’\0’){
if(ch==’(’) WordTable->LeftCurveNum++;
if(ch==’)’) WordTable->RightCurveNum++;
if(StrFlag==1){
StrFlag=0;j=j+1;
WordTable->wt[k].Str[j]=’\0’;
WordTable->wt[k].Length=j;
}
if(ch==’\0’) SentenceEndFlag=1;
}
else{
return 0;
}
i=i+1;
ch=ComBuf[i];
}
if(i if(WordTable->LeftCurveNum==WordTable->RightCurveNum) return 1;
else return 0;
}
else{
return 0;
}
}

输入回显和指令解说履行
void yyshell(void *yydata) reentrant
{
yydata=yydata;
clrscr();
PrintStr(“\t\t***********************************************\n”);
PrintStr(“\t\t* Welcom to use this program *\n”);
PrintStr(“\t\t* Author:YangYi 20020715 *\n”);
PrintStr(“\t\t***********************************************\n\n\n”);

PrintStr(“% “);
while(!ShellEnd){

switch(State){
case StatInputCom:{
if(yygetch(&ch)){
if(ch==13)
{
PrintStr(“\n”);
ComBuf[i+1]=’\0’;
if(i+1==0) PrintStr(“% “);
else
State=StatExeCom;
}
else{
i=i+1;
if((i>=MaxLenComBuf)&&(ch!=8)){
PrintChar(7);
i=MaxLenComBuf-1;
}
else{
if(ch==8){
i=i-2;
if(i<-1) {i=-1;PrintChar(7);}
else{
PrintChar(8);
PrintChar(’ ’);
PrintChar(8);
}
}
else{
PrintChar(ch);
ComBuf[i]=ch;
}
}
}
break;
}
else{
//OSTimeDly(10);
break;
}
}
case StatExeCom:{
if(GetWord(ComBuf,&WordTable)==1&&WordTable.Num!=0){
yystrlwr(WordTable.wt[0].Str);
for(tem=0;tem if(yystrcmp(WordTable.wt[0].Str,ComTable[tem])==0) ComMatchFlag=1;
if(ComMatchFlag){
tem–;
switch(tem){
case 0:{DisplayTask(&WordTable);break;}
case 1:{Kill(&WordTable);break;}
case 2:{PingCommand(&WordTable);break;}
case 3:{UDPCommand(&WordTable);break;}
case 4:{CfgHost(&WordTable);break;}
case 5:{CfgMask(&WordTable);break;}
case 6:{CfgGateway(&WordTable);break;}
case 7:{
//ShellEnd=1;
PrintStr(“\n\tThis Command is limited!\n\n”);
break;
}
case 8:{PrintConfig(&WordTable);break;}
case 9:{clrscr();break;}
case 10:{DisplayHelpMenu(&WordTable);break;}
}
}
else
PrintStr(” Bad command!\n\n”);
}
else{
if(WordTable.Num) PrintStr(” Bad command!\n\n”);
}

ComMatchFlag=0;
State=StatInputCom;
if(ShellEnd) {PrintStr(“\n\n”);}
else PrintStr(“% “);
i=-1;
break;
}
default:{
//ShellEnd=1;
PrintStr(“System fatal error!\n”);
PrintChar(7);PrintChar(7);PrintChar(7);
}
}
}
}

以上是我这次移植uCOS51的一些心得,写出来仅仅让预备在51上运转操作体系的同行们少走弯路并增强运用决心。我强烈引荐我们在自己的51体系中运用uCOS这个简略有用的自己的操作体系。它的巨细应该不是问题,功能上的进步却是明显的。期望此文能对朋友们有所协助,过错在所难免,期望读者纠正。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/changshang/jieda/261768.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部