调了2天的51单片机程序,发现了一个问题,这算不算是Keil C51的BUG?

2019-03-24 17:42发布

本帖最后由 bobde163 于 2016-3-18 11:39 编辑

用Keil C51调了2天的51单片机程序,主要功能是使用定时器0实现一路模拟串口,但是在使用中模拟串口发送的数据全都是0,串口发送的字节帧格式都是对的,一个起位,8个数据位,一个停止位,说明是要发送的数据全都变为了0。使用软件仿真调试,查看汇编代码,反复分析才确定了问题的根本原因,跟51单片机内部的4个寄存器组有莫大的关系。


1、 进入中断前寄存器组从0切换到2_副本.png
1、在进入定时器0的中断函数前,可以看到系统还是使用的是默认的寄存器组0,由于设置中断函数使用寄存器组2,所以在进入中断函数前,除了对原来的运行数据进行入栈操作外,最后还切换到了寄存器组2,这里没有问题。

中断中进入带参数的函数前的参数传递.PNG
2、在中断函数中调用了带参数的函数VUartTransmitByte(*Ptr)(注:Ptr是一个指向字节数据的指针,指针变量地址为0x3D,位于data段)。在图中可以看到在汇编代码中,在实际调用函数前,先对参数进行了传递,使用R7进行参数的传递,之后正式进入函数内部,此处也没有问题。

进入函数时 参数传递给R5.PNG
3、在正式进入函数中时,从汇编代码中可以看到,第一条被执行的指令是MOV R5,0x07;这里就是第一个出问题的地方,结合后面的代码分析,这条指令的作用是将传递进来的参数(存在寄存器组2中的R7中)又转存到R5中,R7又作其他用途。但是这条指令却用的是0x07地址,0x07是寄存器组0中的R7寄存器,此时系统选用的还是寄存器2,应该使用的R7或者0x17,这是导致数据错误的第一个地方。

进行移位和与操作的汇编代码.PNG
4、之后便执行到移位操作和与操作部分if(dat & (0x01 << (TxBitCnt - 1))),从汇编出来的代码可以看到TxBitCnt - 1这一步是没有问题的,结果存放在R7中,接下来就是要执行移位操作,代码先是将需要移位的位数(就是TxBitCnt - 1的值,存放在R7中)放到R0中MOV R0,0x07;才会进入循环移位的代码部分,但是这条指令系统却是使用寄存器组0中的R7,而不是存储真正位数和寄存器组2中的R7,导致移位结果全为0。这个错误是和上一条错误是一样的。


5、我去掉定时器0中断使用寄存器组2的设置(using 2),系统就会使用默认的寄存器组0,只是进入中断函数前,会先把R0到R7的值压入堆栈,会多一些开销,但是程序运行就对了,发送的数据也都是正确的。


6、这个问题曾经遇到过,调了一周,最后只知道是只要在中断中调用个别函数,就会导致发送函数异常,没有找到原因,现在看来可能也是这个原因导致的。
6、疑问:这个问题的产生是和我代码有关系吗?这个不知道大家有没有遇到过呢?这算不算是一个Keil C51的BUG呢?


此帖出自小平头技术问答
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
10条回答
ntmusic
2019-03-26 02:19
个人感觉,既然用C语言了,就不要涉及到编译器编译层面上的控制,比如指定寄存器组(Using)。提高执行效率的想法很好,但目前编译器的优化和单片机的执行速度已经大大提高了,强行指定一方面不利于程序移植,一方面容易带来异常,得不偿失。如果真的要提高效率,可以直接用汇编和C混编。最后对于你这个问题,我觉得你只是指定了在中断函数中强制寄存器组,但在中断中调用的函数是在中断函数外被编译的,并不属于中断函数域,所以不受中断函数的寄存器组指定影响。

一周热门 更多>