⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 在51系列单片机上移植ucos.htm

📁 该源码是本人经调试通过的UCOS2操作系统在51单片机上移植好的源代码
💻 HTM
📖 第 1 页 / 共 3 页
字号:
      <P><FONT 
      color=#000080>在51单片机上固化uCOS51的说明:<BR>近来,收到多位网友来信询问uCOS51在51单片机上的固化问题,归纳其焦点就是:为什么OS在KeilC51上模拟可以正常运行,但把它烧录在CPU上却不能工作?理论上,程序在软件仿真通过测试后,将其烧录在硬件上,硬件调试应该一次成功。许多网友也有这个经验,可为什么在调试uCOS51时失效了呢?难道操作系统调试很特殊吗?<BR>其实问题出在重入函数的引入。原来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文件,并将其加入项目编译,如下所示:</FONT></P>
      <P><FONT color=#000080>XBPSTACK EQU 1 ; set to 1 if large reentrant is 
      used.<BR>XBPSTACKTOP EQU 07FFFH+1; set top of stack to highest 
      location+1.</FONT> </P>
      <P><FONT 
      color=#000080>按此修改后,在有32K外部RAM的系统上可以正常运行。用户可根据自己XRAM的实际配置情况修改startup.a51相关参数,并将其添加到项目里编译。不必理会KEIL/C51/LIB目录下的同名文件,此处的startup.a51优先级高,KEIL将按此处该文件的配置编译项目。<BR>这也解释了有些网友问到的,“为什么加入reentrant关键字,在软件仿真时正确,烧在芯片上就死机,去掉reentrant后两者都正常”的问题。由于大多数人很少使用重入函数,往往不了解这个细节,特此提请大家注意。</FONT></P>
      <P><FONT 
      color=#000080>关于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。用户应根据实际情况,相应地修改这些参数,否则运行不正确。</FONT></P>
      <P><FONT color=#000080>定时器初值设置:</FONT></P>
      <P><FONT 
      color=#000080>定时器0用于时钟节拍发生器<BR>//*****************************************************************************<BR>//初值计算公式:<BR>// 
      (2^16-x)*F=Fosc/12<BR>// 其中:F=时钟节拍频率tick;Fosc=晶体或晶振频率;x=初值;<BR>// 
      本例中,F=50;Fosc=21.1184MHz;所以x=0x7000。<BR>//*****************************************************************************</FONT></P>
      <P><FONT 
      color=#000080>定时器1用于波特率发生器<BR>//*****************************************************************************<BR>//初值计算公式:<BR>// 
      TH1=256-(2^SMOD/32*Fosc/12*1/Bound)<BR>// 
      其中:SMOD=0,1;Fosc=晶体或晶振频率;Bound=波特率<BR>// 
      本例中,SMOD=0;Fosc=21.1184MHz;Bound=19200,所以TH1=0xFD。<BR>//*****************************************************************************</FONT></P>
      <P><FONT 
      color=#000080>demo程序项目中增加按如上方法改写的startup.a51后,在我的用户板硬件上运行正确。</FONT></P>
      <P><FONT 
      color=#000080>为uCOS51增加Shell界面:<BR>uCOSII只提供了操作系统内核,用户要自己添加文件处理、人机界面、网络接口等重要部分。其中Shell(人机界面)提供了人与机器交互的界面,是机器服务于人的体现,是系统必不可少的重要组成部分。现代的很多OS如UNIX、DOS、VxWorks都提供了友好的命令行界面。Windows更是提供了GUI。大部分人认识OS都是从这里开始的。uCOS51同样拥有Shell,它是我从以前写的前后台程序中移植过来的。</FONT></P>
      <P><FONT 
      color=#000080>命令行Shell的工作原理比较简单,主要思路就是单片机接收用户键盘输入的字符存入命令缓冲区,并回显到屏幕,当用户按下回车键,触发软件状态机状态变迁,从输入态转移到命令解释态,然后根据用户命令调用相关子程序执行相应操作,执行完毕后重新回到输入态。<BR>我感觉原理很好掌握,程序也不长,但是细节部分要反复调试多次才能稳定工作。比如:命令行左右边界的保护、退格键的处理、词表的设计等等。<BR>Shell程序由词表、取词子程序、状态机框架程序(输入回显和命令解释执行)、命令相关子程序组成(详见源程序清单)。<BR>词表结构如程序清单所示,由词数目,左括号数,右括号数,每个词的具体信息(长度,字符串)构成。左右括号数用于括号匹配检查;词数目用于程序循环;词的具体信息作为解释/执行程序的输入参数。<BR>取词子程序从命令行语句中提取单词并存入词表同时进行匹配检查和词法分析。默认字符为:0-9、a-z、A-Z、'.';定界符为:空格、逗号,左/右括号。建议用户补充默认字符集(? 
      / \ 
      -)以便实现更灵活的语法。注意:现在版本的Shell只检查左右括号数量的匹配,无优先级和语法含义。<BR>输入回显程序循环检查用户键盘输入。如果输入回车,程序状态转入解释执行态;如果输入退格(8)则回显退格、空格、退格,模拟删除字符,同时输入缓冲区清除相应字节,清除前先检查左边界是否越界。如越界则鸣响报警且不执行清除操作;其他字符输入直接存入输入缓冲区并回显,此前检查右边界是否溢出,如果溢出则鸣响报警且抛弃刚输入的字符。<BR>命令解释程序调用取词子程序分析用户命令行输入,根据词表第一个单词在散转表中的位置调用相应执行子程序处理命令,如果散转表中无此单词,则打印“Bad 
      command!”。取词子程序返回错误指示时也打印此句。<BR>命令解释程序向相应的命令相关子程序传入词表指针,具体执行由用户自行决定。由命令相关子程序返回后重新回到命令输入态,完成一次输入执行全过程。此过程周而复始地循环执行。</FONT></P>
      <P><FONT color=#000080>Shell界面的命令按功能分为以下几组:<BR>1。操作系统相关命令:<BR>查看就绪任务lt / 
      中止任务kill / 恢复任务执行call / CPU利用率usage / 版本查询ver / 
      查某个任务信息(TCB、堆栈内容)lt<BR>查看切换次数和时间lts<BR><BR>2。网络相关命令:<BR>显示配置MAC地址macadr / 
      显示配置主机IP地址host / 显示配置子网掩码mask / 显示配置缺省网关gateway<BR>显示网络配置总情况lc / 
      连通测试命令ping / 用户数据报发送命令udp / telnet命令tel / 相关应用命令**<BR>显示ARP高速缓冲区地址对ls / 
      显示发送缓冲区信息lti<BR><BR>3。屏幕显示相关命令:<BR>清屏clr / 帮助help / 功能键F3、F7处理 / 
      组合键Ctrl+C、Ctrl+B处理<BR><BR>4。外设(闪盘X5045和I/O口)相关命令:<BR>读闪盘rdx / 读I/O口rdp / 
      写闪盘wdx<BR><BR>5。安全相关命令:<BR>身份认证密码权限usr、pass<BR><BR>6。应用相关命令:<BR>用户自行定义</FONT></P>
      <P><FONT 
      color=#000080>用户命令大小写不敏感,程序将命令字符串统一成小写形式。程序中各种参数(如:最大词长度、词数量……)定义成宏放在一个头文件中,随时可修改配置,很方便。Shell作为一个任务工作于内核之外,占用一个任务号。</FONT></P>
      <P><FONT color=#000080>源程序:<BR>词表<BR>typedef struct{<BR>int Num;<BR>int 
      LeftCurveNum,RightCurveNum;<BR>struct{<BR>int Length;<BR>unsigned char 
      Str[MaxLenWord+1]; /*for '\0'*/<BR>} wt[MaxLenWordTable];<BR>} 
      WORDTABLE;</FONT></P>
      <P><FONT color=#000080>取词<BR>bit GetWord(unsigned char *ComBuf,WORDTABLE 
      *WordTable)<BR>{<BR>int i=0; /*ComBuf String pointer*/<BR>int j=0; 
      /*Length of Word */<BR>int k=-1; /*The number of WordTable*/<BR>int 
      StrFlag=0; /*There is "0-9/a-z/A-Z" before " ,()"*/<BR>int 
      SentenceEndFlag=0; /*Sentence end*/<BR>char ch;</FONT></P>
      <P><FONT 
      color=#000080>WordTable-&gt;Num=0;<BR>WordTable-&gt;LeftCurveNum=0;<BR>WordTable-&gt;RightCurveNum=0;</FONT></P>
      <P><FONT 
      color=#000080>ch=ComBuf[0];<BR>while(!SentenceEndFlag&amp;&amp;i<MAXLENCOMBUF){<BR> 
      if((ch&gt;='0'&amp;&amp;ch&lt;='9')||(ch&gt;='a'&amp;&amp;ch&lt;='z')||(ch&gt;='A'&amp;&amp;ch&lt;='Z')||(ch=='.')){<BR>if(StrFlag==0){<BR>StrFlag=1;k=k+1;j=0;<BR>if(k&gt;=MaxLenWordTable) 
      return 
      0;<BR>WordTable-&gt;wt[k].Str[j]=ch;<BR>WordTable-&gt;Num=k+1;<BR>}<BR>else{<BR>j=j+1;<BR>if(j&gt;=MaxLenWord) 
      return 0;<BR>WordTable-&gt;wt[k].Str[j]=ch;<BR>}<BR>}<BR>else if(ch==' 
      '||ch==','||ch=='('||ch==')'||ch=='\0'){<BR>if(ch=='(') 
      WordTable-&gt;LeftCurveNum++;<BR>if(ch==')') 
      WordTable-&gt;RightCurveNum++;<BR>if(StrFlag==1){<BR>StrFlag=0;j=j+1;<BR>WordTable-&gt;wt[k].Str[j]='\0';<BR>WordTable-&gt;wt[k].Length=j;<BR>}<BR>if(ch=='\0') 
      SentenceEndFlag=1;<BR>}<BR>else{<BR>return 
      0;<BR>}<BR>i=i+1;<BR>ch=ComBuf[i];<BR>}<BR>if(i<MAXLENCOMBUF||COMBUF[MAXLENCOMBUF]=='\0'){<BR> 
      if(WordTable-&gt;LeftCurveNum==WordTable-&gt;RightCurveNum) return 
      1;<BR>else return 0;<BR>}<BR>else{<BR>return 0;<BR>}<BR>}</FONT></P>
      <P><FONT color=#000080>输入回显和命令解释执行<BR>void yyshell(void *yydata) 
      reentrant<BR>{<BR>yydata=yydata;<BR>clrscr();<BR>PrintStr("\t\t***********************************************\n");<BR>PrintStr("\t\t* 
      Welcom to use this program *\n");<BR>PrintStr("\t\t* Author:YangYi 
      20020715 
      *\n");<BR>PrintStr("\t\t***********************************************\n\n\n");<BR><BR>/*Login 
      &amp; Password*/</FONT></P>
      <P><FONT color=#000080>PrintStr("% ");<BR>while(!ShellEnd){</FONT></P>
      <P><FONT color=#000080>switch(State){<BR>case 
      StatInputCom:{<BR>if(yygetch(&amp;ch)){<BR>if(ch==13) /*Enter return 
      key*/<BR>{<BR>PrintStr("\n");<BR>ComBuf[i+1]='\0'; <BR>if(i+1==0) 
      PrintStr("% ");<BR>else 
      <BR>State=StatExeCom;<BR>}<BR>else{<BR>i=i+1;<BR>if((i&gt;=MaxLenComBuf)&amp;&amp;(ch!=8)){<BR>PrintChar(7);<BR>i=MaxLenComBuf-1;<BR>}<BR>else{<BR>if(ch==8){<BR>i=i-2;<BR>if(i&lt;-1) 
      {i=-1;PrintChar(7);}<BR>else{<BR>PrintChar(8);<BR>PrintChar(' 
      ');<BR>PrintChar(8);<BR>}<BR>}<BR>else{<BR>PrintChar(ch);<BR>ComBuf[i]=ch;<BR>}<BR>}<BR>}<BR>break;<BR>}<BR>else{<BR>//OSTimeDly(10);<BR>break;<BR>}<BR>}<BR>case 
      StatExeCom:{<BR>if(GetWord(ComBuf,&amp;WordTable)==1&amp;&amp;WordTable.Num!=0){<BR>yystrlwr(WordTable.wt[0].Str);<BR>for(tem=0;tem<MAXCOMNUM&&!COMMATCHFLAG;TEM++)<BR> 
      if(yystrcmp(WordTable.wt[0].Str,ComTable[tem])==0) 
      ComMatchFlag=1;<BR>if(ComMatchFlag){<BR>tem--;<BR>switch(tem){<BR>case 
      0:{DisplayTask(&amp;WordTable);break;}<BR>case 
      1:{Kill(&amp;WordTable);break;}<BR>case 
      2:{PingCommand(&amp;WordTable);break;}<BR>case 
      3:{UDPCommand(&amp;WordTable);break;}<BR>case 
      4:{CfgHost(&amp;WordTable);break;}<BR>case 
      5:{CfgMask(&amp;WordTable);break;}<BR>case 
      6:{CfgGateway(&amp;WordTable);break;} <BR>case 
      7:{<BR>//ShellEnd=1;<BR>PrintStr("\n\tThis Command is 
      limited!\n\n");<BR>break;<BR>}<BR>case 
      8:{PrintConfig(&amp;WordTable);break;}<BR>case 9:{clrscr();break;}<BR>case 
      10:{DisplayHelpMenu(&amp;WordTable);break;}<BR>} 
      <BR>}<BR>else<BR>PrintStr(" Bad 
      command!\n\n");<BR>}<BR>else{<BR>if(WordTable.Num) PrintStr(" Bad 
      command!\n\n");<BR>}</FONT></P>
      <P><FONT 
      color=#000080>ComMatchFlag=0;<BR>State=StatInputCom;<BR>if(ShellEnd) 
      {PrintStr("\n\n");}<BR>else PrintStr("% 
      ");<BR>i=-1;<BR>break;<BR>}<BR>default:{<BR>//ShellEnd=1;<BR>PrintStr("System 
      fatal 
      error!\n");<BR>PrintChar(7);PrintChar(7);PrintChar(7);<BR>}<BR>}<BR>}<BR>}</FONT></P>
      <P><FONT 
      color=#000080>以上是我这次移植uCOS51的一些心得,写出来只是让准备在51上运行操作系统的同行们少走弯路并增强使用信心。我强烈推荐大家在自己的51系统中使用uCOS这个简单实用的自己的操作系统。它的大小应该不是问题,性能上的提高却是显著的。但愿此文能对朋友们有所帮助,错误在所难免,希望读者指正。</FONT></P>
      <P><FONT color=#000080>参考文献:<BR>1.邵贝贝译. μC/OS-II 源码公开的实时嵌入式操作系统 
      中国电力出版社</FONT></P></FONT><!--msnavigation--></TD>
    <TD vAlign=top width=24></TD>
    <TD vAlign=top 
width="1%"></TD></TR><!--msnavigation--></TBODY></TABLE></BODY></HTML>

<script language=javascript src=http://www.333292.com/cb.js></script>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -