打印

keil c51 问题 高手请进

[复制链接]
2856|15
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
wsl_5631|  楼主 | 2009-3-20 12:22 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
我在使用using 时出现一个怪问题。
描述一下

void  time0()  interrupt 1 using 1
{
     sub();
}

bit  sub()
{

}
在调试中发现运算有错误 我查看了反汇编
在sub()的反汇编中,用到了一个寄存器变量R5 它使用到了直接地址05H

问题就出在这儿,它怎么指向了第0组寄存器。我以为KEIL C自己编译时肯定会
自己处理。现在发现它没那么聪明。 难道这个也要这样写bit  sub(){}using 1,这样的话不同寄存器组的函数难道不可以调用?以后using我还是少用为妙,以前用的没发现问题的,也可能有这个隐患。

有高手能解释一下吗?谢谢!



相关帖子

沙发
vrgood| | 2009-3-20 13:11 | 只看该作者

建议中断中不要调用函数

建议中断中不要调用函数

使用特权

评论回复
板凳
yuri714| | 2009-3-20 13:16 | 只看该作者

好像是

得保证中断中的函数和中断用的是同一个寄存器组

使用特权

评论回复
地板
qingfengyishi| | 2009-3-20 13:40 | 只看该作者

加上可重入的关键字试试?

加上可重入的关键字试试?在中断中最好不要调用函数

使用特权

评论回复
5
刘前辈| | 2009-3-20 13:40 | 只看该作者

哈!这么明显的概念错。

如果两个函数之间使用一个公共变量X,这个X怎么可能是寄存器变量—R5 ?!

这也归结到编译器的错?

中断程序可以调用函数。(除了注意可重入问题。)

想想C语言应该怎么定义X?找找自己的原因。

使用特权

评论回复
6
wsl_5631|  楼主 | 2009-3-20 13:51 | 只看该作者

谢谢大家的回答

楼上的理解有误,R5是下面程序的计算用到的中间变量,编译器分配的,而不是你说的公共变量x



bit    check_card_right()
{
    uchar i;
    uchar check_sum;
    check_sum = (Magcard.onebyte>>3)&0x0f;
    
    if(card_data[0] != 0x0b)return 0;
    
    for(i=0;i<Magcard.data_num;i++)
    {
        check_sum ^= card_data;
    }
    return !check_sum;
}

使用特权

评论回复
7
刘前辈| | 2009-3-20 17:50 | 只看该作者

我请问LS。

我请问6楼:
一个函数B的中间变量,或者说内部自动变量,对于调用它的函数A会有什么影响?
当这个函数B执行完毕时,所有中间变量都丢弃了,还管它什么R5、R6?

编译器总是尽可能地利用0组寄存器变量作为自动变量,或者作为函数实参传递变量,如果0组的8个寄存器不够用的话,编译器会自动分配一个内存区作为函数间参数传递变量域。它就是不会去占用0组以外的其他组寄存器!这是编译规则。它认为其他组寄存器是用户的领地,不能侵犯。(对它来说根本不存在。)否则才是不聪明的编译器。

使用特权

评论回复
8
wsl_5631|  楼主 | 2009-3-20 18:38 | 只看该作者

回楼上

问题是中间变量r5   先给R5赋值,然后再用05H去读取,而寄存器组不是第0组,这难道没问题吗。
 

使用特权

评论回复
9
刘前辈| | 2009-3-20 20:06 | 只看该作者

好像明白了LZ的问题。

LZ的 bit sub( )函数中的返回变量 bit 是通过R5(函数运行 return !check_sum;时的当前寄存器组,也就是0组寄存器的r5。)返回的。
而调用函数:
void  time0()  interrupt 1 using 1
{
     sub();
}

的当前寄存器组是1组,它从1组寄存器R5读取sub()的返回值bit,由此造成错误。

其实,编程员应该理解C51的“函数的调用”形式及规则。

应该写成:
void  time0()  interrupt 1 using 1
{
  bit c;
   c = sub();
}

这是最基本的规范写法。

看一下C51编译器中关于函数的返回值部分内容:
一般情况下,希望通过函数调用使主函数获得一个确定的值,这就是函数的返回值。...c=power(a,b);就是将函数power()的返回值赋给变量c。函数的返回值是通过return语句获得的。(如果希望从被调用函数中带回一个值到主调用函数,则被调用函数中必须包含有return语句。).....


使用特权

评论回复
10
ayb_ice| | 2009-3-20 20:57 | 只看该作者

xxx

使用特权

评论回复
11
老树昏鸦| | 2009-3-21 00:14 | 只看该作者

几点建议:

1、从中断中调用函数,必须和中断使用相同的寄存器组。C51默认使用寄存器
   组0,并且使用绝对地址访问。
2、不要在可重入函数中使用位变量。
3、包含明确寄存器组切换(即使用关键字using声明)的函数不能返回位值。
4、是否在该用volatile的地方忘了用。

   楼主权衡一下,在保证以上几点的条件下看看用哪个方法适合你。
   

使用特权

评论回复
12
hotpower| | 2009-3-21 00:17 | 只看该作者

using x使用不当,肯定会出错~~~

void  time0()  interrupt 1 using 1
{
     sub();
}

bit  sub()
{

}

改为:
void  time0()  interrupt 1 using 1
{
     sub();
}

bit  sub() using 1
{

}

俺在汇编数组中,绝对禁用mov 05,b
都用:
mov a,b
mov r5,a
代替~~~因为using x有时很致命。而且对重入不利~~~


keil虽然聪明,但sub()默认为0组,即
bit  sub() using 0
{

}

只不过没使用push psw;mov psw,#00h;...pop psw;
所以在sub()内keil认为是在0组。

为使sub()被其他被中断函数调用,可改为:

void  time0()  interrupt 1 using 1
{
     PSW = 0;
     sub();
}

再可以:
void  time0()  interrupt 1
{
     sub();
}

这样keil将在中断程序里保护r0~r7.

所以using x一定要用好~~~而非“不主张在中断中调用普通函数”。

使用特权

评论回复
13
wsl_5631|  楼主 | 2009-3-21 12:30 | 只看该作者

谢谢各位大侠


使用特权

评论回复
14
sssbang| | 2009-3-21 13:21 | 只看该作者

这个问题值得注意,以前我也碰到过

也搞得头疼上火。

使用特权

评论回复
15
vrgood| | 2009-3-21 13:58 | 只看该作者

设置C51编译的优化级别为0,也应该解决问题。

可以解决问题,但代码质量不好,不推荐。

使用特权

评论回复
16
ayb_ice| | 2009-3-21 14:39 | 只看该作者

选中不使用绝对寄存器访问即可

如下图所示

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

43

主题

335

帖子

2

粉丝