基于8051单片机的超级终端仿真1_第1页
基于8051单片机的超级终端仿真1_第2页
基于8051单片机的超级终端仿真1_第3页
基于8051单片机的超级终端仿真1_第4页
基于8051单片机的超级终端仿真1_第5页
已阅读5页,还剩8页未读 继续免费阅读

下载本文档

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

文档简介

1、基于8051单片机的超级终端仿真,新年最新奉献    超级终端,其实就一个输入输出设备,搞ARM的,这个东西可能再熟悉不过了,XP下就自带了一个,在 程序->附件->通讯工具->超级终端,可以看到。     我们通常是用基于串口的超级终端,即通过串口实现输入输出,来与CPU交互,控制CPU的执行。     先看仿真工程,如图8051.JPG (118.44 KB)2007-1-3 15:48     终端显示结果:下图ht.jpg (42

2、.94 KB)2007-1-3 15:48    这里似乎出现了乱码,可先别乱下结论,原来是proteus自带的串口终端根本就没有解析VT100协议,很多命令自符直接打印出来了的原因,比如,控制终端前颜色,背景色,清屏等一些命令,如果想完整仿真这个工程,建议通过虚拟串口,用XP自带的终端来实现交互,而不要用proteus的那个,如何连接虚拟串口,这个问题搜索论坛吧,有个兄弟写的教程已经很详细了,我也不多此一举了。    这里只支持4条命令,help;prompt;clear;reboot;需要可以自行添加,比如内存查看命令等等,自己也动动手修改,这样才有

3、进步!   今天觉得无聊,详解它,代码解释   第一步,任何代码入口都从main函数开始,我们来看看:Copy to clipboard - CODE:void main(void)InitHyperTerminal();while(1)  RunHyperTerminal();哇,就这么几行,也太简单了吧,某人写得流水灯好象也比这复杂啊,话是没错,解释。InitHyperTerminal(); 初始化超级终端,很好理解,看看里面究竟在干什么?Copy to clipboard - CODE:void InitHyperTermina

4、l(void)TMOD |= 0x20;   /* timer1, mode 2, 8 bit reload */SCON  = 0x50;   /* serial mode 1, 8 bit uart, enable receive  */PCON  = 0x80;   /* SMOD = 1, double baud */ TH1   = 0xFF;  /* baud = 57600, fosc = 11.0592MHZ */TL1

5、   = 0xFF;  RI    = 0;    /* clear receive flag */TI    = 0;   /* clear send flag */TR1   = 1;    /* start timer1 */ES    = 1;   /* enable serial interrupt */EA    = 1;   /* enable

6、 all interrupt */CursorPosion = 0;ExecCommandFlag = 0;memset(&SerialBuffer0,'0',MAX_SERIAL_BUFFER_SIZE);memcpy(&PromptBuffer0,"->>",MAX_PROMPT_BUFFER_SIZE);SerialSendStr(F_LIGHTGREEN);SerialSendStr(B_BLACK);SerialSendStr(CLEARSCREEN);SerialSendStr("-rn");Ser

7、ialSendStr("  The 8051 Hyper Terminal,by JJJrn");SerialSendStr("   rn");SerialSendStr("-rn");SerialSendStr("rn");SerialSendStr(&PromptBuffer0);   首先初始化串口,使用定时器1,模式2,自动装载8位,波特率57600,这样快多了,呵呵,使能串口中断,总中断,初始化全局变量,然后设置超级终端,黑底绿字,最经典

8、的配色,清屏,向终端打印一些信息,比如版权啊什么的,尽管没人相信这东西,最后打印提示符,就跟DOS提示符一样的东西。继续。while(1) 好理解,死循环。里面就一个函数RunHyperTerminal(); 猜也猜得到,这家伙肯定就是干活的。里面是啥呢,好奇。Copy to clipboard - CODE:void RunHyperTerminal(void)if(ExecCommandFlag)  ExecCommand(&SerialBuffer0);  SerialSendStr(&PromptBuffer0); &#

9、160;memset(&SerialBuffer0,'0',MAX_SERIAL_BUFFER_SIZE);  CursorPosion = 0;  ExecCommandFlag = 0;   就这么点,感觉失落啊,之前可满是期待,以为长篇大论呢   解释,判断有没有命令要执行,是个全局变量标志,记得在初始化函数里还初始化过。没有就很简单了,什么也不干,有了呢?ExecCommand(&SerialBuffer0);执行命令,怎么执行,等下分析。SerialSendStr(&

10、;PromptBuffer0);送提示符,友好嘛。命令执行完备肯定要等待下一次命令输入的。memset(&SerialBuffer0,'0',MAX_SERIAL_BUFFER_SIZE);清空缓冲区,没什么可以解释的,为了下次正确执行必须这样做,对于memset这个函数不知道干啥的兄弟,可要回去好好会会谭浩强了CursorPosion = 0;ExecCommandFlag = 0;这两个也没啥好说的,复位变量。   在进入核心前,我们先看看中断服务程序,这个可不是以main函数为主线,典型的前后台系统,单任务程序的典型处理方法,以后有机会我会给大

11、家介绍另一种处理方法,事情标志加事情驱动的思想,这个思想得益于周立功的USB接口芯片PDIUSBD12驱动源码,(不是打广告,我的公司跟周立功是竞争对手,誓不两立,别人的优点我们还是要让他放光芒的)只不过被我概括出来。  打个岔,源码是最好的老师,要想提高自己的编程水平,必须多读源码,即使你自己很能写,如果你的编程思想不好,写出来的全是垃圾,而编程思想哪里来,读别人的源码自己悟,世界上的任何一个编程天才都是这条路,可能又有人问,哪有那么多源码啊,跟别人要个源码比登天还难,我跟你说,不愿给源码的人编程水平肯定还没你强(涉及核心技术的除外),你也没必要去费神了。可能因为我工作的

12、关系吧,推荐读linux源代码,600万行,各种芯片驱动程序都有,读吧,读完你准是高手中的高手,估计读到这篇文章的都是些初学者,那我建议2年后,你将它提上日程,在这之前有很多中小型代码可以读,vivi,三星ARM的bootloader,u-boot通用bootloader,ucos,ucgui.去开源网站看吧,切记读是读他的编程思想,编程技巧,而不是代码的功能。串口中断服务程序Copy to clipboard - CODE:void SerialInterrupt(void) interrupt 4 using 3char SbufTemp;if(RI)  RI = 0;

13、  SbufTemp = SBUF;  switch(SbufTemp)    case 0x08:  case 0x06:  case 0x07:  case 0x7E:  case 0x7F:   if(CursorPosion > 0)       CursorPosion-;    SerialSendByte(0x08);  

14、60; SerialSendByte(' ');    SerialSendByte(0x08);      SerialBufferCursorPosion = '0'   break;  case 'r':  case 'n':  case '0':   SerialSendByte('r');   SerialSen

15、dByte('n');   ExecCommandFlag = 1;   break;     case 't':   break;  default:   if(CursorPosion < MAX_SERIAL_BUFFER_SIZE)       SerialBufferCursorPosion = SbufTemp;    SerialSendByte

16、(SbufTemp);    CursorPosion+;      else       CursorPosion = 0;    memset(&SerialBuffer0,'0',MAX_SERIAL_BUFFER_SIZE);    SerialSendStr("rn Warnning:Your command string is too long!rnrn");    SerialS

17、endStr(&PromptBuffer0);      break;    别看这稍长,其实很好理解,如果有串口接收中断标志,代表收到一个字符,清RI标志,缓存至局部变量SbufTemp,判断字符,退格键,删除键,则将缓冲区指针减一,再更新屏幕显示,回车键,代表输入结束,置全局变量标志,有待解析字符,其余的则就是用户输入的有效字符了,注意,这里有个缓冲区溢出判断,很关键。  好了,中断服务程序理解了,即用户输入的字符都到了SerialBuffer这个数组里,那我们接下来的就是解析了Co

18、py to clipboard - CODE:void ParseArgs(char *argstr,char *argc_p,char *argv, char *resid)char argc = 0;char c;PARSESTATE stackedState,lastState = PS_WHITESPACE;while (c = *argstr) != 0)  PARSESTATE newState;  if (c = '' && lastState != PS_STRING && lastStat

19、e != PS_ESCAPE)   break;  if (lastState = PS_ESCAPE)     newState = stackedState;    else if (lastState = PS_STRING)     if (c = '"')        newState = PS_WHITESPACE;    *argstr

20、 = 0;       else        newState = PS_STRING;        else if (c = ' ') | (c = 't')     *argstr = 0;   newState = PS_WHITESPACE;     else if (c = '"') &

21、#160;    newState = PS_STRING;   *argstr+ = 0;   argvargc+ = argstr;     else if (c = '')      stackedState = lastState;   newState = PS_ESCAPE;     else      if (last

22、State = PS_WHITESPACE)        argvargc+ = argstr;      newState = PS_TOKEN;    lastState = newState;  argstr+;argvargc = NULL;if (argc_p != NULL)  *argc_p = argc;if (*argstr = '')   *argstr+ = '0

23、9;*resid = argstr;   这段代码是分析参数,即将用户输入的字符串比如“prompt 8051>>”分析出参数的个数,以及将每个参数分别存在数组里,一个二维数组,这段代码是借鉴VIVI里面的,涉及到编译原理里的一些知识。Copy to clipboard - CODE:void ExecCommand(char *buf)char argc,*argv8,*resid,i;COMMAND *Command = 0;while(*buf)    memset(argv,0,sizeof(argv); 

24、; ParseArgs(buf, &argc, argv, &resid);  if(argc > 0)     for(i = 0; i < MAX_COMMAND_NUM; i+)       Command = &CommandListi;     if(strncmp(Command->CommandName,argv0,strlen(argv0) = 0)     break

25、;    else     Command = 0;      if(Command = 0)       SerialSendStr(" Could not found "");    SerialSendStr(argv0);    SerialSendStr("" commandrn");    SerialSendStr(&quo

26、t; If you want to konw available commands, type 'help'rnrn");          else       Command->CommandFunc(argc,argv);       buf = resid;  这是执行命令,即根据刚才分析的结果,运行特定功能的函数。这里涉及到一个数据类型Copy to clipboard -

27、CODE:typedef struct const char *CommandName;void (*CommandFunc)(char argc, const char *argv);const char *HelpString;COMMAND;第一个命令的名字,第二个命令的执行函数指针,带有两个参数,很像C的main函数吧,这样可以传任何命令参数,第三个简单,帮助字符串Copy to clipboard - CODE:COMMAND CommandListMAX_COMMAND_NUM = "help",Help," help - Command help&q

28、uot;,"prompt",Prompt," prompt <string> - Change a prompt","clear",Clear," clear - Clear screen","reboot",Reboot," reboot - Reboot the MCU"定义了四个命令,声明是不是很简单呢。Copy to clipboard - CODE:void Help(char argc, const char *argv)char i;argv = a

29、rgv;switch(argc)case 1:  for(i = 0; i < MAX_COMMAND_NUM; i+)     SerialSendStr(CommandListi.HelpString);   SerialSendStr("rn");    SerialSendStr("rn");  break;default:  SerialSendStr(" Invalid

30、 'help' command: too many argumentsrn");  SerialSendStr(" Usage:rn");  SerialSendStr("     helprn");  break;这是help函数,就是打印帮助信息,好简单,不说了Copy to clipboard - CODE:void Prompt(char argc, const char *argv)switch(argc)case 2:

31、  if(strlen(argv1) >= MAX_PROMPT_BUFFER_SIZE)     SerialSendStr(" Warnning:Your argument is too long!rnrn");   break;    memcpy(PromptBuffer,argv1,MAX_PROMPT_BUFFER_SIZE);  SerialSendStr(" Prompt is chagned to &q

32、uot;");  sprintf(&SerialBuffer0,"%s"rnrn",&PromptBuffer0);  SerialSendStr(&SerialBuffer0);  break;default:  SerialSendStr(" Invalid 'prompt' command: too few or many argumentsrn");  SerialSendStr(&quo

33、t; Usage:rn");  SerialSendStr("     prompt <string>rn");  break;改变提示符,比较人性化啊,即将要设置的提示符丢进PromptBuffer就OK了Copy to clipboard - CODE:void Clear(char argc, const char *argv)argv = argv;switch(argc)case 1:  SerialSendStr(CLEARSCREEN);

34、  break;default:  SerialSendStr(" Invalid 'clear' command: too many argumentsrn");  SerialSendStr(" Usage:rn");  SerialSendStr("     clearrn");  break;清屏指令,清除超级终端上的显示,VT100的功能,SerialSendStr(CL

35、EARSCREEN);Copy to clipboard - CODE:void Reboot(char argc, const char *argv)argv = argv;switch(argc)case 1:  (*(void(*)()0)();   break;default:  SerialSendStr(" Invalid 'reboot' command: too many argumentsrn");  SerialSendStr(" Usage:rn&

36、quot;);  SerialSendStr("     rebootrn");  break;  看名字意思,就知道,让单片机重启,热启动,不是硬复位,看看代码(*(void(*)()0)(); 好晦涩啊,可能你都怀疑这能编译通过吗?事实证明,这不但能编译通过,而且还能让单片机重起。  好,我们看看,这段代码是怎么来的?  我们都知道CPU一上电就从0地址开始运行, 而一复位PC指针就指向0地址,如果我们能将PC指针设置为0,既从0地址运行,不就可以复位了吗?  用C语言去控制PC指针可没那么容易,LJMP它可没有,怎么办呢?  复习一个概念,函数,实际是一个地址,一个函数执行体的入口地址,函数指针,是指向某个函数地址的指针变量。如果函数执行体的地址是0,那么肯定就从那儿开始运行了。  看个普通的函数void test(void)怎么调用这个函数呢,大家都知道,这样就可以调用了  test();没错,完全正确,但大家可能忽略了一点,这只是个简化的写法,完整的写法应该是

温馨提示

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

评论

0/150

提交评论