调了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条回答
Li_Lei
1楼-- · 2019-03-25 04:50
 精彩回答 2  元偷偷看……
bobde163
2楼-- · 2019-03-25 09:42
huo_hu 发表于 2016-3-18 13:19
这个结果是对的,using指定这个函数使用某寄存器组,你的uarttransimtbyte函数没指定这所以不操作那个寄存 ...

我设置了定时器中断服务函数要使用寄存器组2,并且状态寄存器PSW中也显示系统已经切换到寄存器组2了,那在整个中断函数的执行过程中,应该一直是要使用寄存器组2才对啊;
另外,像你说的,我的VUartTransmitByte()函数没有指定使用哪个寄存器组,那它是不是应该会确定使用某一个寄存器组?但是从汇编代码来看,它是横跨了寄存器组0和寄存器组2,有使用寄存器组2中的R7,R5,R0,R6等,也有通过直接寻址访问0x07(寄存器组0中的R7),函数里既使用了组0,也使用了组2,这又要怎么解释呢?
Li_Lei
3楼-- · 2019-03-25 15:11
bobde163 发表于 2016-3-18 14:51
我设置了定时器中断服务函数要使用寄存器组2,并且状态寄存器PSW中也显示系统已经切换到寄存器组2了,那 ...

不一定,全局量是系统安排的,只有局部变量才组2.
不指定和using 0 是一样的。

using的使用和编译器分配的空间有关系,如果没用到就当没有。
bobde163
4楼-- · 2019-03-25 17:42
 精彩回答 2  元偷偷看……
Li_Lei
5楼-- · 2019-03-25 22:15
bobde163 发表于 2016-3-19 13:13
但是从汇编出来的代码来看,在中断里被调用的函数VUartTransmitByte()里面同时使用了组2和组0,这个就 ...

你把源程序贴上来哪天有空了看看
bobde163
6楼-- · 2019-03-25 22:26
本帖最后由 bobde163 于 2016-3-21 10:07 编辑
huo_hu 发表于 2016-3-19 17:00
你把源程序贴上来哪天有空了看看

那就劳烦版主帮忙看看,模拟串口的代码如下:
V_Uart.c (9.09 KB, 下载次数: 5) 2016-3-21 10:06 上传 点击文件名下载附件

一周热门 更多>