打印

关于keil数组(RAM)访问的问题

[复制链接]
4295|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
8410430|  楼主 | 2010-5-27 14:57 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
编译背景如下:
;IC BODY          : STC12C5A32AD
;IDE           : KEIL uV3  C51 COMPILER V8.16   8级优化
;OSCILLATOR       : XTAL=12MHz

最近在原程序基础上修改程序,出现如下一个问题:
原程式中定义一数组:unsigned char xdata level_ad[16] ={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

后因需要修改为:unsigned char xdata level_ad[24] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

该数组上电后均会在外部EEPROM中读取数值添将数据补齐。
进行操作。
操作指令如下:
if(work_opt == w_pstart){
  target_ad = level_ad[bar[level_bar]];
}
else if(work_opt == w_tstart){
  target_ad = level_ad[bar[level_bar]];
}
else if(work_opt == w_wstart){
  target_ad = watt_ad;
}
else if(work_opt == w_ad){
  target_ad = level_ad[motor_level];
}
else{
  target_ad = 0;
}

原始程式没有问题,修改后程式运行时:
执行 else if(work_opt == w_ad){
  target_ad = level_ad[motor_level];}
语句,当motor_level = 0 ,target_add取得的值为255  问题点实际应该为0;执行其他语句时可得到实际值。
将语句更改为:
else if(work_opt == w_ad){
  target_ad = level_ad[motor_level];
  if(motor_level == 0)target_ad = level_ad[0];
}
编译后汇编代码如下:
   163:         else if(work_opt == w_ad){
C:0x4C61    E57C     MOV      A,program_no(0x7C)
C:0x4C63    B4101A   CJNE     A,#0x10,C:4C80
   164:                 target_ad = level_ad[motor_level];
C:0x4C66    7451     MOV      A,#level_ad(0x51)
C:0x4C68    257B     ADD      A,motor_level(0x7B)
C:0x4C6A    F582     MOV      DPL(0x82),A
C:0x4C6C    E4       CLR      A
C:0x4C6D    3400     ADDC     A,#user1_bar(0x00)
C:0x4C6F    F583     MOV      hand_hight_time(0x83),A
C:0x4C71    E0       MOVX     A,@DPTR
C:0x4C72    78A9     MOV      R0,#target_ad(0xA9)
C:0x4C74    F6       MOV      @R0,A
   165:                 if(motor_level == 0)target_ad = level_ad[0];
C:0x4C75    E57B     MOV      A,motor_level(0x7B)
C:0x4C77    700E     JNZ      C:4C87
C:0x4C79    900051   MOV      DPTR,#level_ad(0x0051)
C:0x4C7C    E0       MOVX     A,@DPTR
C:0x4C7D    F6       MOV      @R0,A
   166:         }
C:0x4C7E    8007     SJMP     C:4C87
问题依旧。


附运行正常程序,改段代码编译:
   163:         else if(work_opt == w_ad){
C:0x4C59    E57B     MOV      A,work_opt(0x7B)
C:0x4C5B    B41011   CJNE     A,#0x10,C:4C6F
   164:                 target_ad = level_ad[motor_level];
C:0x4C5E    78A8     MOV      R0,#motor_level(0xA8)
C:0x4C60    E6       MOV      A,@R0
C:0x4C61    2477     ADD      A,#area4_opt(0x77)
C:0x4C63    F582     MOV      hand_hight_time(0x82),A
C:0x4C65    E4       CLR      A
C:0x4C66    3400     ADDC     A,#user1_bar(0x00)
C:0x4C68    F583     MOV      DPH(0x83),A
C:0x4C6A    E0       MOVX     A,@DPTR
C:0x4C6B    08       INC      R0
C:0x4C6C    F6       MOV      @R0,A
   165:         }
C:0x4C6D    8004     SJMP     C:4C73

相关帖子

沙发
8410430|  楼主 | 2010-5-27 15:02 | 只看该作者
实际应用中,以上问题是可以通过其他算法进行规避而不影响功能,
但出现上面问题的问题点一直无法找到,让我无法安心、放心。

盼好心人,能指点一下。

使用特权

评论回复
板凳
ayb_ice| | 2010-5-27 15:32 | 只看该作者
这种情况要一步一步调试
要看当时的值才有意义的
如果软件模拟是有可能不正确的,我也遇到过的

使用特权

评论回复
地板
冷漠| | 2010-5-27 16:27 | 只看该作者
本帖最后由 冷漠 于 2010-5-27 16:49 编辑

瞎看:
正常程序中,motor_level看上去是一个数组常量指针,起始位置在RAM-0xA8.相当于:
else if(work_opt == w_ad){
  target_ad = level_ad[ motor_level[0] ];
}

你自己修改后的程序,motor_level看上去是一个char变量,位置在0x7B。编译结果与C语句对应一致。

else if(work_opt == w_ad){
  target_ad = level_ad[motor_level];
}

前者间接寻址,后者直接寻址,相同C语句,同一编译器编译出2种结果?好玩,怎么玩出来的,给咱讲讲。想起匠人写的“寻址关系理解”,这里为什么要用间接寻址?

如果未修改正常程序也可以拿来实验的话,发现问题岂不是很简单?也加入下面程序,看看编译结果的奥妙。
if(motor_level == 0)target_ad = level_ad[0];


C:0x4C5E    78A8     MOV      R0,#motor_level(0xA8)
C:0x4C60    E6       MOV      A,@R0
我也还没理解好,理解错了请原谅。正好也给咱讲讲课。

使用特权

评论回复
5
8410430|  楼主 | 2010-5-27 18:05 | 只看该作者
楼上错了,原始程式也是
else if(work_opt == w_ad){
  target_ad = level_ad[motor_level];
}
怎么什么时候冒出个
else if(work_opt == w_ad){
  target_ad = level_ad[ motor_level[0] ];
}
吓我一跳还以为错成这样,我还能编译的过。阿弥陀佛,楼上的看错了。

回三楼的,我不是软件模拟出错,是实际测试出错,一步调了,还是没有见到一丝好转迹象,能否提供你以前问题的解决思路给我参考下?

使用特权

评论回复
6
ayb_ice| | 2010-5-28 08:25 | 只看该作者
我怀疑你这是数组访问越界造成的

使用特权

评论回复
7
救火车| | 2010-5-28 08:51 | 只看该作者
楼上说得对。
"target_ad = level_ad[motor_level];}
语句,当motor_level = 0 ,target_add取得的值为255  问题点实际应该为0;执行其他语句时可得到实际值。"
调试建议:
1、在程序开头的位置加上
motor_level = 0;
target_ad = level_ad[motor_level];
观察target_ad的值。应该是0.如果不是0再作分析。
2、在数组声明的地方之前,再声明一个数组。
unsigned char xdata temp[10];
unsigned char xdata level_ad[24]= ......
如果加上以后,问题全消失,那么恭喜你。你的程序其他地方存在数组越界。重点检查这个数组之前的XDATA数组的使用情况。注意:下标是从0开始的,比如数组里声明到10,下标最大只能到9.

其他的可能性先不说了。你先试试这两个实验。

使用特权

评论回复
8
冷漠| | 2010-5-28 10:11 | 只看该作者
本帖最后由 冷漠 于 2010-5-28 10:30 编辑

好事来了。4楼冷漠谈及了LZ的2个编译结果之间的差别,——同一编译器怎么会有两种编译结果?虽然最终结果是一样的,但是值得??。那么LZ如此肯定地说“冷漠错了。”这岂不等于是说自己错了?那就值得好好查查了。

其实不用太紧张:
1、  target_ad = level_ad[ motor_level[0] ];
2、  target_ad = level_ad[ motor_level ];

两者最终结果一样,无所谓对与错。但是肯定间接寻址比直接寻址效率低。冷漠的问题是“你的正常程序为什么这里编译出了间接寻址”。显然前者用的编译器不是一个版本或者后者编译器优化改进升级了?注意看下面编译结果:

附运行正常程序,改段代码编译:
   163:         else if(work_opt == w_ad){
C:0x4C59    E57B     MOV      A,work_opt(0x7B)
C:0x4C5B    B41011   CJNE     A,#0x10,C:4C6F

   164:      target_ad = level_ad[motor_level];
C:0x4C5E    78A8     MOV      R0,#motor_level(0xA8)
C:0x4C60    E6       MOV      A,@R0
       // motor_level指针间接寻址。
C:0x4C61    2477     ADD      A,#area4_opt(0x77)
C:0x4C63    F582     MOV      hand_hight_time(0x82),A



再看冷漠的实验程序结论:
冷漠不是在谈LZ 程序的错误原因,只是在谈2者程序之间的差别。

使用特权

评论回复
9
冷漠| | 2010-5-28 10:18 | 只看该作者

再看冷漠的实验程序结论:

本帖最后由 冷漠 于 2010-5-28 10:28 编辑

再看冷漠的实验程序结论:
两者被编译器视为一样!除了寻址方式不一样。后面编译器版本高,把level_ad[ motor_level[0] ];  
优化为或者事先编译计算为:
level_ad[ *motor_level ];      // 然后直接寻址


使用特权

评论回复
10
8410430|  楼主 | 2010-5-28 10:57 | 只看该作者
高兴中,楼上的两位好心人(入行不深,不想以高人想称,因为不知道我问的问题是不是特别低级,乱乱的叫去,总觉不妥,见谅!)
按照救火车同志的方法2试验,问题确实没有了。
经查: level_ad[24]数组确实存在越界访问的现象,上一数组是我的显存数组,在这之前有一个全屏操作,将数据置成255了,所以出现了上面的问题。

修改前的程式XDATA数据的排布由于和修改后的数据排布不一样,所以以前的程序虽然也有数组访问越界的问题,但不会在运行中反映出来,因为运行上段程序后,我就直接软复位了。

阿弥陀佛,万幸,看来以后对数组,指针什么进行操作的时候,还是要小心加小心。

再次感谢各位好心人!

使用特权

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

本版积分规则

8

主题

45

帖子

0

粉丝