搜索
bottom↓
回复: 11

关于keil中for循环的问题,有遇到的朋友进贴大家讨论

[复制链接]

出0入0汤圆

发表于 2013-1-7 11:46:45 | 显示全部楼层 |阅读模式
for(i=0; i<8; i++)和for(i=8; i>0; i--)在使用中有什么区别呢,都是执行八次,但是实际上在keil编译后下载运行的效果却不同,有时两个都可以,有时这个可以那个不可以,有时那个可以这个却出了问题。而这个问题我目前遇到的大多都出现在1302时钟芯片上,其他到没有什么。
void DS1302WriteByte(uchar Dat)
{
  char i;
  ACC = Dat;
  DS1302_CLK = 0;                                                                        //初始化时钟线为低电平
  for(i=0; i<8; i++)
  {            
    DS1302_DAT = ACC0;                   //送数据到数据线
    DS1302_CLK = 0;

    DS1302_CLK = 1;                                                                //上升沿时钟,送数据到DS1302
    ACC = ACC >> 1;                                                         //ACC右移一位,准备传输下一位数据
  }
}
uchar DS1302ReadByte()
{
  unsigned char i;
  ACC = 0;
       
  for(i = 0;i < 8;i++)
  {
    ACC = ACC >> 1;                                                                 //先右移一位
    DS1302_CLK = 0;                                                                 //拉低,这时DS1302准备好数据在数据线上
    ACC7 = DS1302_DAT;                                                        //读取数据线上的数据
    DS1302_CLK = 1;                                                                 //拉高,结束本次数据传输,准备传输下一位
                          
  }

  return (ACC);                                                                                 //返回        读出的数据
}
这两个函数用for(i=8; i>0; i--)正常,但是用for(i=0; i<8; i++)就不正常了。有遇到这类情况且知道原因的么?
难道是跟keil的优化有关系?
先查看反汇编看看,有大侠知道的告诉下,不甚感激!

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入8汤圆

发表于 2013-1-7 11:53:52 | 显示全部楼层
for(i=0; i<7; i++)

出0入0汤圆

 楼主| 发表于 2013-1-7 12:02:45 | 显示全部楼层
liwei_jlu 发表于 2013-1-7 11:53
for(i=0; i

这是运行八次么?不是吧!

出0入0汤圆

 楼主| 发表于 2013-1-7 12:09:16 | 显示全部楼层
   
for(i=8; i>0; i--)形式的反汇编如下
35: void DS1302WriteByte(uchar Dat)  
    36: {  
    37:   char i;
    38:   ACC = Dat;
C:0x1F39    EF       MOV      A,R7
    39:         DS1302_CLK = 0;         //初始化时钟线为低电平
C:0x1F3A    C2B5     CLR      DS1302_CLK(0xB0.5)
    40:   for(i=8; i>0; i--)
C:0x1F3C    7F08     MOV      R7,#week(0x08)
    41:   {              
    42:     DS1302_DAT = ACC0;                  //送数据到数据线
C:0x1F3E    A2E0     MOV      C,ACC0(0xE0.0)
C:0x1F40    92B4     MOV      DS1302_DAT(0xB0.4),C
    43:                 DS1302_CLK = 0;
    44:  
C:0x1F42    C2B5     CLR      DS1302_CLK(0xB0.5)
    45:     DS1302_CLK = 1;                                        //上升沿时钟,送数据到DS1302
C:0x1F44    D2B5     SETB     DS1302_CLK(0xB0.5)
    46:     ACC = ACC >> 1;                             //ACC右移一位,准备传输下一位数据
C:0x1F46    C3       CLR      C
C:0x1F47    13       RRC      A
    47:   }  
C:0x1F48    DFF4     DJNZ     R7,C:1F3E

for(i=0; i<8; i++)形式的反汇编如下
    35: void DS1302WriteByte(uchar Dat)  
    36: {  
    37:   char i;
    38:   ACC = Dat;
C:0x1EEB    EF       MOV      A,R7
    39:         DS1302_CLK = 0;         //初始化时钟线为低电平
C:0x1EEC    C2B5     CLR      DS1302_CLK(0xB0.5)
    40:   for(i=0; i<8; i++)
C:0x1EEE    E4       CLR      A
C:0x1EEF    FF       MOV      R7,A
    41:   {              
    42:     DS1302_DAT = ACC0;                  //送数据到数据线
C:0x1EF0    A2E0     MOV      C,ACC0(0xE0.0)
C:0x1EF2    92B4     MOV      DS1302_DAT(0xB0.4),C
    43:                 DS1302_CLK = 0;
    44:  
C:0x1EF4    C2B5     CLR      DS1302_CLK(0xB0.5)
    45:     DS1302_CLK = 1;                                        //上升沿时钟,送数据到DS1302
C:0x1EF6    D2B5     SETB     DS1302_CLK(0xB0.5)
    46:     ACC = ACC >> 1;                             //ACC右移一位,准备传输下一位数据
C:0x1EF8    C3       CLR      C
C:0x1EF9    13       RRC      A
    47:   }  
C:0x1EFA    0F       INC      R7
C:0x1EFB    EF       MOV      A,R7
C:0x1EFC    B408F1   CJNE     A,#week(0x08),C:1EF0
    48: }

由上看,就在代码最后有两条不一样而已,无解。不过从这里也能学到一个好的知识,使用for(i=8; i>0; i--)相对较好,这是对于51单片机来说。因为有DJNZ这条指令。

出0入0汤圆

发表于 2013-1-7 14:24:57 | 显示全部楼层
有时这个可以那个不可以,有时那个可以这个却出了问题
出问题的时候都是一模一样的代码跟编译配置么- -

出0入93汤圆

发表于 2013-1-7 14:38:57 | 显示全部楼层
这个问题分成三个小问题来看:

1、你把代码展开后看:
第一个,i依次是0, 1, 2, 3, 4, 5, 6, 7
第二个,i依次是8, 7, 6, 5, 4, 3, 2, 1
假如循环中使用到了i,你说有区别么?当然具体到这个题目,没有这个问题。

2、51中直接操作ACC,如果你没有十分的把握,你这样会出错的。
很显然,第一个会出错。因为递减跳转可以只通过通用寄存器R0~R7实现,而递增则不会,它会通过ACC传递。因为你手动改变了ACC的值,于是程序递增失败……

3、一般情况下,递减的比递增的效率高。

出0入0汤圆

发表于 2013-1-7 14:46:58 来自手机 | 显示全部楼层
这种直接操作ACC的代码还是别用了吧,移植性太差了。用一个变量不就行了?其他的交给编译器做吧

出0入93汤圆

发表于 2013-1-7 14:47:26 | 显示全部楼层
dashashi 发表于 2013-1-7 14:24
有时这个可以那个不可以,有时那个可以这个却出了问题
出问题的时候都是一模一样的代码跟编译配置么- - ...

仔细看看我上面说的第二条,然后我给你改一下,你自己编译看有没有问题:
  1. void DS1302WriteByte(uchar Dat)
  2. {
  3.   char i;
  4.   DS1302_CLK = 0;                                                                        //初始化时钟线为低电平
  5.   for(i=0; i<8; i++)
  6.   {            
  7.     DS1302_DAT = (bit)(Dat & 1);                                               //送数据到数据线
  8.     DS1302_CLK = 0;

  9.     DS1302_CLK = 1;                                                                //上升沿时钟,送数据到DS1302
  10.     Dat >>= 1;                                                                        //右移一位,准备传输下一位数据
  11.   }
  12. }

  13. uchar DS1302ReadByte()
  14. {
  15.   unsigned char i;
  16.   uchar Dat = 0;
  17.         
  18.   for(i = 0;i < 8;i++)
  19.   {
  20.     Dat >>= 1;                                                                         //先右移一位
  21.     DS1302_CLK = 0;                                                                 //拉低,这时DS1302准备好数据在数据线上
  22.     if(DS1302_DAT) Dat |= 0x80;                                                 //读取数据线上的数据
  23.     DS1302_CLK = 1;                                                                 //拉高,结束本次数据传输,准备传输下一位                           
  24.   }

  25.   return (Dat);                                                                           //返回读出的数据
  26. }
复制代码
如果为了效率的考虑,可以将ACC全部改成B,函数入口时_push_(B),函数返回时_pop_(B),当然这样仍然有风险,但具体到你这个问题,是没有风险的。

出0入0汤圆

 楼主| 发表于 2013-1-7 14:54:48 | 显示全部楼层
我试试不使用ACC看看怎么样。ACC也严重音响可移植性!

出0入0汤圆

 楼主| 发表于 2013-1-7 15:55:33 | 显示全部楼层
不使用ACC没问题了,使用位运算吧,移植性也好,具体情况具体分析吧,要求不严格位运算很好。

出0入0汤圆

发表于 2013-1-7 16:15:09 | 显示全部楼层
6L说的很有道理

出0入0汤圆

 楼主| 发表于 2013-1-7 16:35:45 | 显示全部楼层
dashashi 发表于 2013-1-7 16:15
6L说的很有道理

6楼正解!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-18 09:07

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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