关于KeilC51 Debug的时候观察变量总是0x0000的问题

开发环境(蓝色粗体字为特别注意内容)
1,软件环境:Keil UV2、Keil UV4、Keil UV5。

2,硬件环境:STC12C5A60S2。

3,参考文献:https://blog.csdn.net/snow416/article/details/6407177

在使用keil uv5开发一个单片机小程序的时候,发现了一个小bug,于是使用keil自带的debug功能来单步调试,调试过程中发现了一个严重的问题,就是进入断点之后,在Call Stack+Locals窗口查看变量值都是0x0000,Keil调试无法查看变量值,现象如下:

这让我很是郁闷,记得之前好像遇到过类似的情况,但是最终都不了了之了。这次决定把这个问题优雅的解决掉!

1)怀疑是keil版本太高的原因造成这个问题。

于是又安装了较低版本的Keil UV4,问题依然如此。

随后又安装了Keil UV2,问题依旧。灵机一动,随手用UV2创建了一个test project,发现调试竟然是正常的,变量值能够正常显示!随后又换其他高版本的keil运行test project,发现调试也是正常!

2)于是想到是不是编译模式的问题

我们知道,keil编译选项中的Memory Model有三种模式,分别为:

1、Small: variables in DATA

2、Compact: variables in PDATA

3、Large: variables in XDATA

这三种模式下,变量保存的位置不一样。打开工程配置,发现工程选择的是第二种模式即Compact模式,于是改为选择Small模式,编译,报错如下:

Rebuild target 'Target 1'
compiling wanda.c...
compiling uart.c...
linking...
*** WARNING L16: UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESS
    SEGMENT: ?PR?_STRTOU32?UART
*** WARNING L16: UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESS
    SEGMENT: ?PR?_UARTSENDLOG?UART
*** ERROR L107: ADDRESS SPACE OVERFLOW
    SPACE:   DATA    
    SEGMENT: ?DT?_U32TOSTR?UART
    LENGTH:  001DH
*** ERROR L107: ADDRESS SPACE OVERFLOW
    SPACE:   DATA    
    SEGMENT: ?DT?_UART_SEND_STR?UART
    LENGTH:  000EH
*** ERROR L107: ADDRESS SPACE OVERFLOW
    SPACE:   DATA    
    SEGMENT: ?DT?_STRTOU32?UART
    LENGTH:  000DH
*** ERROR L107: ADDRESS SPACE OVERFLOW
    SPACE:   DATA    
    SEGMENT: ?DT?READTEMP?WANDA
    LENGTH:  0008H
*** ERROR L107: ADDRESS SPACE OVERFLOW
    SPACE:   DATA    
    SEGMENT: ?DT?_SHOWSTRING?WANDA
    LENGTH:  0008H
*** ERROR L107: ADDRESS SPACE OVERFLOW
    SPACE:   DATA    
    SEGMENT: ?DT?_UARTSENDLOG?UART
    LENGTH:  0007H
*** ERROR L107: ADDRESS SPACE OVERFLOW
    SPACE:   DATA    
    SEGMENT: ?DT?_DELAY?WANDA
    LENGTH:  0006H
*** ERROR L107: ADDRESS SPACE OVERFLOW
    SPACE:   DATA    
    SEGMENT: ?DT?MAIN?WANDA
    LENGTH:  0005H
*** ERROR L107: ADDRESS SPACE OVERFLOW
    SPACE:   DATA    
    SEGMENT: ?DT?_SHOWCHAR?WANDA
    LENGTH:  0003H
*** ERROR L107: ADDRESS SPACE OVERFLOW
    SPACE:   DATA    
    SEGMENT: ?DT?_UARTSENDSTR?UART
    LENGTH:  0003H
*** ERROR L107: ADDRESS SPACE OVERFLOW
    SPACE:   DATA    
    SEGMENT: ?DT?_TMPDELAY?WANDA
    LENGTH:  0002H
*** ERROR L107: ADDRESS SPACE OVERFLOW
    SPACE:   DATA    
    SEGMENT: ?DT?READONECHAR?WANDA
    LENGTH:  0002H
*** ERROR L107: ADDRESS SPACE OVERFLOW
    SPACE:   DATA    
    SEGMENT: ?DT?_WRITEONECHAR?WANDA
    LENGTH:  0002H
*** ERROR L107: ADDRESS SPACE OVERFLOW
    SPACE:   DATA    
    SEGMENT: ?DT?_DELAYMS?WANDA
    LENGTH:  0001H
*** ERROR L107: ADDRESS SPACE OVERFLOW
    SPACE:   DATA    
    SEGMENT: ?DT?INIT_DS18B20?WANDA
    LENGTH:  0001H
*** ERROR L107: ADDRESS SPACE OVERFLOW
    SPACE:   DATA    
    SEGMENT: ?DT?_LCD_WRITE_COM?WANDA
    LENGTH:  0001H
*** ERROR L107: ADDRESS SPACE OVERFLOW
    SPACE:   DATA    
    SEGMENT: ?DT?_LCD_WRITE_DAT?WANDA
    LENGTH:  0001H
*** ERROR L107: ADDRESS SPACE OVERFLOW
    SPACE:   DATA    
    SEGMENT: ?DT?_UARTSENDBYTE?UART
    LENGTH:  0001H
Program Size: data=236.0 xdata=0 code=3684
Target not created.
Build Time Elapsed:  00:00:01

全局变量太多了!于是选择第三种模式即Large模式,编译,Debug,发现问题解决:

但是把hex文件烧写到单片机运行,发现运行慢了许多~~~~这三种模式有什么区别呢?按照参考文献的思想,下面对这三种模式进行详细的分析:

Memory Model:用鼠标点击Memory Model的下拉箭头,会有3个选项:


Small:变量存储在内部ram里;
small模式下,再入函数的堆栈是设在idata中的
Compact:变量存储在外部ram里,使用页8位间接寻址;compact模式下,再入函数堆栈是设在pdata中的
Large:变量存储在外部Ram里,使用16位间接寻址;

我们一般使用Small来存储变量,就是说单片机优先把变量存储在内部ram里,如果内部ram不够了,才会存到外部去。Compact的方式要自己通过程序来指定页的高位地址,编程比较复杂,如果外部ram很少,只有256个字节,那么对该256个字节的读取就比较快,用MOVX @Ri,A 或MOVX A,@Ri指令。如果超过256字节,那么要不断地进行切换的话,就比较麻烦。Compact模式适用于比较少的外部ram的情况。Large模式,是指变量会优先分配到外部ram里,用MOVX A,@DPTR或MOVX @DPTR,A来读取。要注意的是,3种存储方式都支持内部256字节和外部64k字节的ram。区别是变量的优先(或默认)存储在哪里的区别。除非你不想把变量存储在内部ram,才使用后面的Compact,Large模式。因为变量存储在内部ram里,运算速度比存储在外部ram要快的多,大部分的应用都是选择Small的模式。

使用Small的模式:也不是说变量就不可以存储在外部,一样可以存储在外部,只是你要指定,比如:
unsigned char xdata a;那么变量a就存储在外部的ram。
unsigned char a;变量存储在内部ram。
使用Large的模式
unsigned char xdata a;那么变量a就存储在外部的ram。
unsigned char a;变量存储在外部ram。 
这就是区别,就是说这几个选项只是影响没有特别指定变量的存储空间的时候,默认存储在哪里,比如上面的变量定义unsigned char a。

如果在变量声明时未声明变量的存储器类型,则该变量的存储器类型,由程序的存储模式来决定。
小模式(small model):默认data区
紧凑模式(compact model):默认pdata区
大模式(large model):默认xdata区

备注:

1、修改了源代码之后必须先点编译,然后再点击调试运行,这样调试的时候才能使得改动生效

2、编译的时候选择合适的代码优化选项也能够减小内存占用比如level 0占用的空间就很大,一般选择level 8!

猜你喜欢

转载自blog.csdn.net/pang9998/article/details/82954748