关于keil中for循环的问题,有遇到的朋友进贴大家讨论
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的优化有关系?
先查看反汇编看看,有大侠知道的告诉下,不甚感激! for(i=0; i<7; i++) liwei_jlu 发表于 2013-1-7 11:53 static/image/common/back.gif
for(i=0; i
这是运行八次么?不是吧!
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这条指令。 有时这个可以那个不可以,有时那个可以这个却出了问题
出问题的时候都是一模一样的代码跟编译配置么- - 这个问题分成三个小问题来看:
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、一般情况下,递减的比递增的效率高。 这种直接操作ACC的代码还是别用了吧,移植性太差了。用一个变量不就行了?其他的交给编译器做吧
dashashi 发表于 2013-1-7 14:24 static/image/common/back.gif
有时这个可以那个不可以,有时那个可以这个却出了问题
出问题的时候都是一模一样的代码跟编译配置么- - ...
仔细看看我上面说的第二条,然后我给你改一下,你自己编译看有没有问题:void DS1302WriteByte(uchar Dat)
{
char i;
DS1302_CLK = 0; //初始化时钟线为低电平
for(i=0; i<8; i++)
{
DS1302_DAT = (bit)(Dat & 1); //送数据到数据线
DS1302_CLK = 0;
DS1302_CLK = 1; //上升沿时钟,送数据到DS1302
Dat >>= 1; //右移一位,准备传输下一位数据
}
}
uchar DS1302ReadByte()
{
unsigned char i;
uchar Dat = 0;
for(i = 0;i < 8;i++)
{
Dat >>= 1; //先右移一位
DS1302_CLK = 0; //拉低,这时DS1302准备好数据在数据线上
if(DS1302_DAT) Dat |= 0x80; //读取数据线上的数据
DS1302_CLK = 1; //拉高,结束本次数据传输,准备传输下一位
}
return (Dat); //返回读出的数据
}如果为了效率的考虑,可以将ACC全部改成B,函数入口时_push_(B),函数返回时_pop_(B),当然这样仍然有风险,但具体到你这个问题,是没有风险的。 我试试不使用ACC看看怎么样。ACC也严重音响可移植性! 不使用ACC没问题了,使用位运算吧,移植性也好,具体情况具体分析吧,要求不严格位运算很好。 6L说的很有道理 dashashi 发表于 2013-1-7 16:15 static/image/common/back.gif
6L说的很有道理
6楼正解!
页:
[1]