单片机高手请进!keil BUG至于你信不信,反正我是信了!

[复制链接]
 楼主| 发表于 2011-8-16 12:50 | 显示全部楼层 |阅读模式
本帖最后由 ARM_Lover 于 2011-8-16 12:54 编辑

我不知到这到底是是为什么?莫非KeilC有BUG?我想那可能行太小了。但我还是不知道到底是为什么?请那位高高手指点一二!我想知道此问题的一定是高手中的高手!程序原本很大,但是最后我把原因缩小到最小,把程序压缩到了最小,以便各位高手方便查阅!另外需要说明的是,如果吧所有的idata去掉的话,就没有该问题了!:dizzy:
大家可以用任何一个51开发板(如果不是STC11F08XE系列,只需要吧串口初始化略加修改便是了!)都可以进行测试,结果会让你们大吃一惊!原来、可以这样。至于你们信不信,反正我是信了!
对了,你需要吧中断0 引脚与串口接收引脚接起来!我的硬件就那样设计的!
  1. #include "STC11F.H"
  2. #include "config.h"
  3. sbit LED =P0^3;
  4. bit flag_modle0 = 0;
  5. uint8 idata REBUF[20];
  6. uint8 idata data_buffer[20] = "0123456789\n";
  7. //串口初始化
  8. void SerialInit(void)
  9. {
  10. AUXR = 0x11; //STC11F08XE配置
  11. BRT = 0xFD; //启用独立波特率发生器
  12. SCON = 0x50; //工作方式为1,允许接受
  13. PCON = 0x00; //SMOD=0
  14. }
  15. //中断初始化
  16. void InterruptInit(void)
  17. {
  18. IT0 = 1;
  19. EX0 = 1;
  20. AUXR1 = 0x00;
  21. EA = 1;
  22. }
  23. //发送一个字节
  24. void SendByte(const uint8 byte)
  25. {
  26. SBUF = byte;
  27. while(TI == 0);
  28. TI = 0;
  29. }
  30. //从idata区域,发送一个字符串
  31. void SendStr(const uint8 idata * ptr)
  32. {
  33. while(*ptr != '\0')
  34. {
  35. SBUF = *ptr;
  36. while(TI == 0);
  37. TI = 0;
  38. ptr++;
  39. }
  40. }
  41. //获取一个字符串,如“::000300!” ,并存放在idata区域里
  42. uint8 * Gets(uint8 idata *str)
  43. {
  44. while(1)
  45. {
  46. while(RI == 0);
  47. RI = 0;
  48. if(SBUF == '!'){
  49. *str = SBUF;
  50. str++;
  51. *str = '\0';
  52. break;
  53. }
  54. *str = SBUF;
  55. str++;
  56. }
  57. return str;
  58. }

  59. void Puts(uint8 code * ptr)
  60. {
  61. while(*ptr != '\0'){
  62. SBUF = *ptr;
  63. while(TI == 0);
  64. TI = 0;
  65. ptr++;
  66. }
  67. }
  68. //中断0
  69. void Int0() interrupt 0 using 1
  70. {
  71. EX0 = 0;
  72. AUXR1 = 0x00;
  73. if(flag_modle0 == 0) //如果发送模式未定,进入未知接受状态
  74. {
  75. while(RI == 0);
  76. RI = 0;
  77. if(SBUF == ':')
  78. {
  79. uint8 idata *sp = REBUF;
  80. uint8 idata *ep = Gets(sp);
  81. LED = ~LED;
  82. //输入字符串::000300!
  83. //SendStr(strp++)能够正常执行,但是SendByte(*sp)发送结果为'\0',输出"\nCommand Error!\n"
  84. // SendByte(*sp);
  85. // SendByte(*(sp+1));
  86. // SendByte(*(sp+2));
  87. //SendStr(strp++)能够正常执行,SendStr(sp+1) 与SendStr(sp+2)的发送结果与输入的结果一样。
  88. // SendStr(sp+1);
  89. // SendStr(sp+2);
  90. // SendStr(sp+3);
  91. //SendStr(strp++)没有发送结果,SendStr(sp+1)没有发送结果,输出"\nCommand Error!\n"
  92. // SendStr(sp++);
  93. // SendStr(sp++);
  94. // SendStr(sp++);
  95. if(*sp == ':') //:: /ip/mod/boad/!
  96. Puts("Command Right!\n");
  97. else
  98. Puts("\nCommand Error!\n");
  99. }
  100. IE0 = 0;
  101. EX0 = 1;
  102. }
  103. }
  104. void main(void)
  105. {
  106. uint8 *strp = data_buffer;
  107. SerialInit();
  108. InterruptInit();
  109. SendStr(strp++);
  110. SendStr(strp++);
  111. SendStr(strp++);
  112. SendStr(strp++);
  113. while(1);
  114. }
发表于 2011-8-16 13:03 | 显示全部楼层
没把问题说清楚。所以帮不了你。大概看了你的串口程序,这样的程序是不能用的。
 楼主| 发表于 2011-8-16 13:34 | 显示全部楼层
2# DownCloud 原因是这样的。我需要对单片机通过串口进行配置一些参数,但是发送命令是说错误,即程序里面Puts("\nCommand Error!\n");。于是我让单片机把程序受到的内容发出来,结果发现了这一系列的问题。在中断程序里面有三段
1、输入这句话

   SendByte(*sp);
   SendByte(*(sp+1));
   SendByte(*(sp+2));
   输出结果:
   0123456789
   123456789
   23456789
   3456789
   Command Error!
2、输入这3句程序
   SendStr(sp+1);
   SendStr(sp+2);
   SendStr(sp+3);
   输出结果:
   0123456789
   123456789
   23456789
   3456789
   :000300!:000300!:000300!
   Command Error!

3、输入这3句
   SendStr(sp++);
   SendStr(sp++);
   SendStr(sp++);
   输出结果

Command Error!

这下可够明白了么?
不知高手能否给予解答?
我实在是疑惑不解啊??、
发表于 2011-8-16 14:40 | 显示全部楼层
能写出这样的极品程序,当然会疑惑不解了……:lol
建议把代码格式化一下;串口中断只干两个事:把SBUF的数据搬到接收FIFO,把发送FIFO的数据搬到SBUF;命令的拆解和解释执行都放到main函数的主循环里。
 楼主| 发表于 2011-8-16 15:16 | 显示全部楼层
4# mohanwei 我那只是个调试部分,我给你们呈现的是调试出现的现象!我把所有的程序原样搬上去,你们有心思看么?
发表于 2011-8-16 16:01 | 显示全部楼层
3# ARM_Lover
嘿嘿,看不懂,帮不了你。程序浪费的CPU时间太多了。接收不能用死等的方式。发送用死等的方式也不好。
发表于 2011-8-16 16:32 | 显示全部楼层
main()和ISR都调用了SendStr(),而SendStr()没有声明为可重入,LZ编译时没遇到警告么?

看样子好像是指针传递出了问题, 试试这个方法行不行:修改一下编译设置,
options for target'XXX' (就是那个能设置晶振频率的选项卡)---> C51 ---> code optimization--->选中 don't use absolute register access
 楼主| 发表于 2011-8-16 16:44 | 显示全部楼层
6# DownCloud 你的意思我是明白的!我平常的程序也也是基于中断的,但是现在我面对的不是效率,也不是方法。而是为什么寻址会发生错误!这才是真正要解决的问题!我在刚发帖的时候就预料到很多朋友会抓住我的这个问题不放,我想大家是本末倒置,或者曲解了我的意思!在C程序效率我还是比较有自信的的。毕竟我用汇编写了1年的程序,对51结构还是相当的熟悉的!
 楼主| 发表于 2011-8-16 16:53 | 显示全部楼层
7# alicedodo 我感觉这位仁兄的见解还是比较切入主题的。但是在一般的情况下,不可重入函数易导致的错误在我这个调试函数里面是不会发生的。因为,首先上电后,程序马上运行了四次SendStr();(这个函数当然是非常快的,还来不及让我发送数据)。然后一直在while(1);等待过程,直到中断产生。之后不会被调用,也就不会因中断调用SendStr();而产生不可重入函数引发的错误。
发表于 2011-8-16 21:53 | 显示全部楼层
上面和LZ说的一共是两个问题:
1、main()和ISR共同调用非可重入函数可能导致的错误

2、Lz程序里有个返回指针的函数,我觉得问题也可能出在这儿。C代码编译成汇编之后,程序使用寄存器返回指针值。当代码优化级别比较高的时候,编译器默认BANK0寄存器组,那么寻址寄存器的时候会直接用绝对地址,比如说寻址R6,汇编代码可能是MOV 0x06,A这个样子的。
如果ISR使用了非BANK0寄存器组,且代码中调用了返回指针的函数,因为上面的原因,就会出现数据丢失的情况。

上面的第2种情况我以前遇到过,使能don't use absolute register access选项就能解决这个问题。

评分

参与人数 1威望 +1 收起 理由
ARM_Lover + 1

查看全部评分

发表于 2011-8-16 23:06 | 显示全部楼层
既然都汇编这么精通,为啥不看看汇编窗口分析一下。。。
 楼主| 发表于 2011-8-16 23:15 | 显示全部楼层
10# alicedodo 我想应该是你说的问题!但不一定是你说的返回指针的问题。我正在看反汇编,一定要找到问题的根源。
发表于 2011-8-17 03:06 | 显示全部楼层
不懂!这是一个奇迹?
发表于 2011-8-17 08:47 | 显示全部楼层
void SendStr(const uint8 idata * ptr)
代码中多次使用这样的声明方式,可以最大限度的提高效率;
副作用是 const预示着你不能用任何可以改变的变量作为参数
发表于 2011-8-17 09:25 | 显示全部楼层
不懂
发表于 2011-8-17 11:03 | 显示全部楼层
这个代码..看的云里雾里的..
uint8 * Gets(uint8 idata *str)
这个前后指针类型都不统一.
如果去掉idata ..至少类型统一 了,,,当然未必是这个问题..
但是至少写的时候..应该要避免这个情况吧..
idata * 是 1byte的玩意,,, 但是 * 可是 3byte的 数据..
 楼主| 发表于 2011-8-17 11:21 | 显示全部楼层
16# jiemnij 是啊,因为我见了很多调试的程序,所以让人感到困惑!我把最精简的代码发上去!是这样的,我给串口发送“::000300!”字符串,但是结果却是输出“Command Error!);
”,所以我加了很多的调试程序,结果出现了更多的奇怪的现象,就是上面代码里面的问题。
但是至于idata的肯定是没问题的,因为我用到全是idata*。这样效率会很高的!
  1. #include "STC11F.H"
  2. #include "config.h"
  3. sbit LED =P0^3;
  4. bit flag_modle0 = 0;
  5. bit flag_rec = 0;
  6. uint8 temp = 0;
  7. uint8 idata REBUF[20];
  8. uint8 idata data_buffer[20] = "0123456789\n";
  9. //串口初始化
  10. void SerialInit(void)
  11. {
  12. AUXR = 0x11; //STC11F08XE配置
  13. BRT = 0xFD; //启用独立波特率发生器
  14. SCON = 0x50; //工作方式为1,允许接受
  15. PCON = 0x00; //SMOD=0
  16. }
  17. //中断初始化
  18. void InterruptInit(void)
  19. {
  20. IT0 = 1;
  21. EX0 = 1;
  22. AUXR1 = 0x00;
  23. EA = 1;
  24. }
  25. //发送一个字节
  26. void SendByte(const uint8 byte)
  27. {
  28. SBUF = byte;
  29. while(TI == 0);
  30. TI = 0;
  31. }
  32. //从idata区域,发送一个字符串
  33. //获取一个字符串,如“::000300!” ,并存放在idata区域里
  34. uint8 * Gets(uint8 idata *str)
  35. {
  36. while(1)
  37. {
  38. while(RI == 0);
  39. RI = 0;
  40. if(SBUF == '!'){
  41. *str = SBUF;
  42. str++;
  43. *str = '\0';
  44. break;
  45. }
  46. *str = SBUF;
  47. str++;
  48. }
  49. return str;
  50. }

  51. void Puts(uint8 code * ptr)
  52. {
  53. while(*ptr != '\0'){
  54. SBUF = *ptr;
  55. while(TI == 0);
  56. TI = 0;
  57. ptr++;
  58. }
  59. }
  60. //中断0
  61. void Int0() interrupt 0 using 1
  62. {
  63. EX0 = 0;
  64. AUXR1 = 0x00;
  65. if(flag_modle0 == 0) //如果发送模式未定,进入未知接受状态
  66. {
  67. while(RI == 0);
  68. RI = 0;
  69. if(SBUF == ':')
  70. {
  71. uint8 idata *spp = REBUF;
  72. uint8 idata ep = Gets(spp);
  73. if(*spp == '1')
  74. Puts("Command Right!\n");
  75. else
  76. Puts("\nCommand Error!\n");
  77. }
  78. IE0 = 0;
  79. EX0 = 1;
  80. }
  81. }

  82. void main(void)
  83. {
  84. uint8 idata *strp = data_buffer;
  85. SerialInit();
  86. InterruptInit();
  87. while(1);
  88. }
发表于 2011-8-17 11:43 | 显示全部楼层
本帖最后由 jiemnij 于 2011-8-17 11:54 编辑

//发送一个字节
void SendByte(const uint8 byte)
{
SBUF = byte;
while(TI == 0);
TI = 0;
}

   SendByte(*sp);
   SendByte(*(sp+1));
   SendByte(*(sp+2));
   输出结果:
   0123456789
   123456789
   23456789
   3456789
   Command Error!

你只发送一个字节...结果出来字符串..肯定不会的
多半你调试那里.弄错了..或者你原先用sendstr 等函数的..编译后没烧写等等的..
另外你这种问题..最好把问题细化一下..我是看不明白.你到底想要表达的是keil有什么bug

一般情况下,调试出现异常 ,首先怀疑一下自己的代码有没有问题.
编译器出错的概率是非常非常小的..99.9%的情况都是代码问题
就像上面的SendByte 我非常怀疑输出结果

另外调试的时候..你最好先单字节输出结果看看为妙...先把问题细化再说
 楼主| 发表于 2011-8-17 13:37 | 显示全部楼层
18# jiemnij SendByte();发送的是十六进制0,结果在串口里面一ASCII的形式显示不出来。而
Command Error!则是下面那个if……else……发送出来的。
 楼主| 发表于 2011-8-21 15:58 | 显示全部楼层
哎,看来是没人愿意看着问题了。我还是把帖结了呗。实际上好几天前就把问题解决了,可是我还是想看看高手们的见解也意见。结果没人愿意理!问题就是不可重入函数造成的。中断调用了一个不可重入函数,造成了错误,结果我有调用另外一个不可重入函数去调试,结果造成了很对稀奇古怪的现象。不过还是感谢大家的发言。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

0

主题

54

帖子

1

粉丝
快速回复 返回顶部 返回列表