打印

请教:51程序调试—奇怪问题,变量内容被莫名其妙改变

[复制链接]
5742|33
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
gdmgb520|  楼主 | 2009-11-2 11:25 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 gdmgb520 于 2009-11-2 11:36 编辑

#include <reg52.h>
#include <stdio.h>
#include <intrins.h>
#include <string.h>
#include <math.h>
#define uchar unsigned char
#define uint unsigned int

sbit A1=P0^0;
sbit A2=P0^1;
sbit A3=P0^2;
sbit A4=P0^3;
sbit A5=P0^4;
sbit A6=P0^5;
sbit s_led1=P0^6;
sbit s_led2=P0^7;

uchar dat[40]={255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255};

/***************************************************/
/*函数名称:5Ms延时
/*函数功能:
/*调用函数:无
/***************************************************/
void Delay5Ms(void)
{
unsigned int TempCyc = 5552;
while(TempCyc--);
}

/***************************************************/
/*函数名称:串口和定时器0初始化
/*函数功能:
/*调用函数:无
/***************************************************/
void InitSystem(void)
{
SCON = 0x50; //串口工作在方式1;允许接收
PCON = 0x00; // 波特率不*2
TMOD = 0x21; //定时器1工作在方式2,自动重装 //定时器0工作在方式1
TH1 = 0xFD; // 波特率为9600
TR1 = 1; // 定时器1启动计数
ES = 1; // 串口开中断
EA = 1; // 开总中断

// PS=0; //串口低中断优先级
PT0=1; //定时器T0高中断优先级
TR0=1; //启动定时器0
ET0=1; //开定时器0中断
}
/***************************************************/
/*函数名称:串口字节发送
/*函数功能:
/*调用函数:无
/***************************************************/
void Send_Char_Com(uint ch)
{
SBUF=ch;
while(TI==0); //TI为发送中断请求标志,在一帧数据发送完后被置位。所以该语句的意思是等待数据发送完成,即一直等到TI=1
TI=0; //在任何方式中TI都必须由软件清零
}

/***************************************************/
/*函数名称:数据采集
/*函数功能:每被调用进行一次数据采集
/*调用函数:无
/***************************************************/
void DataAcquisition(void)
{
static uint i=0; //定义一个静态变量作为计数器
if ((i & 0x01)!=0) //送地址,地址范围0x00--0x27(0-39)。
A1=1;
else
A1=0;
if ((i & 0x02)!=0)
A2=1;
else
A2=0;
if ((i&0x04)!=0)
A3=1;
else
A3=0;
if ((i&0x08)!=0)
A4=1;
else
A4=0;
if ((i&0x10)!=0)
A5=1;
else
A5=0;
if ((i&0x20)!=0)
A6=1;
else
A6=0;
P2=0xff; //读取P2口数据
dat=(P2 & dat); //低电平——动作,原来为零的位不管新数据是否为零都写零
i++;
if (i==40) //判断是否完成一次采集循环,当然在这种方式下完全可以不定义数组,
{
i=0;
}
}
/***************************************************/
/*函数名称:数据处理
/*函数功能:
/*调用函数:
/***************************************************/
void DataProcessing(void) //!!!!针对一次采集的数据处理
{
uchar j,k,temp;
uint num=0;
// uchar t=0;
for (j=0;j<40;j++)
{
temp=0x01;
for (k=0;k<8;k++)
{
//temp=0x01<<k;
if ((dat[j] & temp)==0) //节点有低电平时认为产生动作
{
num=j+k*40+1;
Send_Char_Com(num);
// Delay400Ms();
}
temp=temp<<1;
}

}
}
/***************************************************/
/*函数名称:定时器0中断
/*函数功能:每中断一次进行一次数据采集
/*调用函数:DataAcquisition()
/***************************************************/
void Timer0 (void) interrupt 1
{
TH0=0x4c;
TL0=0x00; //直接赋值,50ms中断

s_led2=~s_led2;
DataAcquisition();
}

/************************************************/
/*----------------主函数------------------------*/
/************************************************/
void main ()
{
InitSystem(); //初始化定时器0
while(1)
{
DataProcessing();
s_led1=~s_led1;
Delay5Ms();
}

}




我在debug模式下,当运行到77行时dat[0]的值莫名其妙地变成了0x00,本来应该是0xfe的。
哦,介绍一下我的程序。P0口0~5送地址,P2口采集数据(高电平或低电平)。大家能不能帮我看看问题出在哪里!
谢谢!
下面是我的C文件,我用的KeilC。

cs11-09.10.30最简.rar

20.38 KB

相关帖子

沙发
gdmgb520|  楼主 | 2009-11-2 11:37 | 只看该作者
dat=(P2 & dat); //低电平——动作,原来为零的位不管新数据是否为零都写零


这里是dat ,在帖子里改不过来

使用特权

评论回复
板凳
gdmgb520|  楼主 | 2009-11-2 11:38 | 只看该作者
day[i-],不要“-”

使用特权

评论回复
地板
icecut| | 2009-11-2 11:42 | 只看该作者
我以前也遇到过...
解决方法无非是变量声明时马上初始化,否则地址会被重用.

使用特权

评论回复
5
icecut| | 2009-11-2 11:44 | 只看该作者
你的问题估计2楼已经有解答

使用特权

评论回复
6
gdmgb520|  楼主 | 2009-11-2 14:47 | 只看该作者
本帖最后由 gdmgb520 于 2009-11-2 14:48 编辑

谢谢。

我在定义dat【i】数组时初始化了啊
uchar dat[40]={255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255};

把数组元素全部初始化为0xFF了。
我刚刚有调试,发现每次调用串口字节发送函数后就会出问题,好像是离开串口字节发送函数时dat【i】就会变成0x00。

使用特权

评论回复
7
gdmgb520|  楼主 | 2009-11-2 15:36 | 只看该作者
我刚刚把串口发送函数中的三语句
SBUF=ch;
while(TI==0); //TI为发送中断请求标志,在一帧数据发送完后被置位。所以该语句的意思是等待数据发送完成,即一直等到TI=1
TI=0;

都屏蔽掉了,然后加了其它的测试语句(P3^5送高电平,延时5ms再送低电平),发现dat【i】数组的内容不会被莫名其妙的改变。
所以我怀疑还是串口发送函数的问题。
可是串口发送函数就三个语句,在其他工程中使用是没有问题的啊,到底是怎么回事呢?
有没有哪位兄弟能帮帮忙!

使用特权

评论回复
8
冷漠| | 2009-11-2 21:08 | 只看该作者
本帖最后由 冷漠 于 2009-11-2 21:23 编辑

错在这了。
如若照此,dat[0]就应该是0!

;  /***************************************************/
; /**函数名称:数据采集
/*函数功能:每被调用进行一次数据采集
/*调用函数:无
/***************************************************/
; void DataAcquisition(void)

        RSEG  ?PR?DataAcquisition?CS11
DataAcquisition:
        USING        0
                        ; SOURCE LINE # 87
; {
                        ; SOURCE LINE # 88
;     static uchar i=0;                 ;            if ((i & 0x01)!=0)                   //Ë͵ØÖ·£¬µØÖ··¶Î§0x00--0x27(0-39)¡£
                        ; SOURCE LINE # 90
        MOV          A,i?342
        JNB          ACC.0,?C0008
;                 A1=1;
                        ; SOURCE LINE # 91
        SETB         A1
        SJMP         ?C0009
?C0008:
;         else
;                 A1=0;
                        ; SOURCE LINE # 93
        CLR          A1
?C0009:
;         if ((i & 0x02)!=0)
                        ; SOURCE LINE # 94
        MOV          A,i?342
        JNB          ACC.1,?C0010
;                 A2=1;
                        ; SOURCE LINE # 95
        SETB         A2
        SJMP         ?C0011
?C0010:
;         else
;                 A2=0;
                        ; SOURCE LINE # 97
        CLR          A2
?C0011:
;         if ((i&0x04)!=0)
                        ; SOURCE LINE # 98
        MOV          A,i?342
        JNB          ACC.2,?C0012
;                 A3=1;
                        ; SOURCE LINE # 99
        SETB         A3
        SJMP         ?C0013
?C0012:
;         else
;                 A3=0;
                        ; SOURCE LINE # 101
        CLR          A3
?C0013:
;         if ((i&0x08)!=0)
                        ; SOURCE LINE # 102
        MOV          A,i?342
        JNB          ACC.3,?C0014
;                 A4=1;
                        ; SOURCE LINE # 103
        SETB         A4
        SJMP         ?C0015
?C0014:
;         else
;                 A4=0;
                        ; SOURCE LINE # 105
        CLR          A4
?C0015:
;         if ((i&0x10)!=0)
                        ; SOURCE LINE # 106
        MOV          A,i?342
        JNB          ACC.4,?C0016
;                 A5=1;
                        ; SOURCE LINE # 107
        SETB         A5
        SJMP         ?C0017
?C0016:
;         else
;                 A5=0;
                        ; SOURCE LINE # 109
        CLR          A5
?C0017:
;         if ((i&0x20)!=0)
                        ; SOURCE LINE # 110
        MOV          A,i?342
        JNB          ACC.5,?C0018
;                 A6=1;                 
                        ; SOURCE LINE # 111
        SETB         A6
        SJMP         ?C0019
?C0018:
;         else
;                 A6=0;                 
                        ; SOURCE LINE # 113
        CLR          A6
?C0019:
;         P2=0xff;        //¶ÁÈ¡P2¿ÚÊý¾Ý
                        ; SOURCE LINE # 114
        MOV          P2,#0FFH
;         dat=(P2 & dat);        //低电平——动作,原来为零的位不管新数据是否为零都写零
                        ; SOURCE LINE # 115
        MOV          A,#LOW (dat)
        ADD          A,i?342
        MOV          R0,A
        MOV          A,@R0
        ANL          A,P2
        MOV          @R0,A
;         i++;
                        ; SOURCE LINE # 116
        INC          i?342
;         if (i==40)                        //ÅжÏÊÇ·ñÍê³ÉÒ»´Î²É¼¯Ñ »·£¬µ±È»ÔÚÕâÖÖ·½Ê½ÏÂÍêÈ«¿ÉÒÔ²»¶¨ÒåÊý×飬
                        ; SOURCE LINE # 117
        MOV          A,i?342
        CJNE         A,#028H,?C0021
;         {        
                        ; SOURCE LINE # 118
;                 i=0;
                        ; SOURCE LINE # 119
        CLR          A
        MOV          i?342,A
;         }
                        ; SOURCE LINE # 120
; }
                        ; SOURCE LINE # 121
?C0021:
        RET         
; END OF DataAcquisition

cs11.zip

2.74 KB

使用特权

评论回复
9
864| | 2009-11-2 21:21 | 只看该作者
RAM是否已不够用 声明变量时没成功

使用特权

评论回复
10
gdmgb520|  楼主 | 2009-11-3 11:04 | 只看该作者
8# 冷漠

谢谢您!
您能不能再讲一讲,你贴的这个我没有看懂,能不能告诉我具体是哪里有问题。
再次感谢。请您帮帮忙!

使用特权

评论回复
11
ejack| | 2009-11-3 12:38 | 只看该作者
2楼的那行应该就是。
不明白为什么把P2跟个指针相与……
另外,似乎是读寄存器而非读管脚……?记不太清了……

使用特权

评论回复
12
冷漠| | 2009-11-3 20:18 | 只看该作者
这个调试发现故障很容易:

void main ()
{
        InitSystem();        //
        while(1)
        {
                DataProcessing();   //把这行注释掉。只采集不处理。看看
                                // 50ms 采集一次的dat[]数组值对吗。从简单开始。
                s_led1=~s_led1;
                Delay5Ms();

使用特权

评论回复
13
gdmgb520|  楼主 | 2009-11-9 13:46 | 只看该作者
谢谢大家,问题已解决。
原因如下:
我开了串口中断,但是没有写串口中断子函数,所以当调用串口发送子函数发送时,发送完成就好触发串口中断,程序转到串口中断入口地址去执行,但是却找不到中断函数,所以PC就等于0x0000,因此就出现了程序突然跳到主函数的一开始去执行的现象。
还有疑惑:具体dat[i]数组的元素是怎么被改变的我还不清楚。还望大家指教!

使用特权

评论回复
14
冷漠| | 2009-11-9 15:16 | 只看该作者
原来是别人的程序?

void DataAcquisition(void)
{
static uint i=0; //定义一个静态变量作为计数器
if ((i & 0x01)!=0) //送地址,地址范围0x00--0x27(0-39)。
A1=1;
else
A1=0;
if ((i & 0x02)!=0)
........
A6=0;  // 以上为矩阵行选通(硬件5选一),高电平选通:例如00001,00010,
            //      00100,......
P2=0xff; //读取P2口数据
dat=(P2 & dat); //低电平——动作,原来为零的位不管新数据是否为零都写零
i++;
if (i==40) //判断是否完成一次采集循环,当然在这种方式下完全可以不定义数组,
{
i=0;
}
}

有40个bit变量——5X8开关矩阵,低位闭合,是吗?下面就好解释了。
dat[i]=(P2 & dat[i]); //低电平——动作,原来为零的位不管新数据是否为零都写零

使用特权

评论回复
15
gdmgb520|  楼主 | 2009-11-10 15:57 | 只看该作者
可能我没有说清楚,感觉我们之间的理解有些区别。
是320个开关量,八个一组放在40个字节变量里(40个数组元素)。数组是需要定义的,因为我还有一个处理函数一直要循环处理,当定时器中断时才进行一次采集。
我现在的疑惑是,在开了串口中断,却没有写串口中断子函数,但是又通过串口往外发送了东西的情况下,串口中断后PC会等于0x0000。此时系统的其他变量和寄存器的值会改变吗?dat[i]数组元素的值会改变吗?
谢谢你这么热心的给我解答。

使用特权

评论回复
16
ejack| | 2009-11-10 19:18 | 只看该作者
说破天去你这个
dat=(P2 & dat);
也不可能是正确的。你得明白“dat”在编译器的眼里意味着什么。

另外,
串口中断后PC会等于0x0000
也不对,你应当先翻翻书。

使用特权

评论回复
17
冷漠| | 2009-11-11 10:00 | 只看该作者
本帖最后由 冷漠 于 2009-11-11 10:09 编辑

呵呵,终于理解LZ的意思了。且看下面源代码就清楚了。C51程序总是从STARTUP.A51开始执行,PC:0x0000开始是STARTUP.A51代码,它首先将RAM初始化为全“0”。然后才跳到main主程序。
所以当你“串口中断后PC会等于0x0000”异常跳到PC:0x0000时,程序再次从STARTUP执行,将RAM再次初始化为全“0”!——这就是异常改变所有RAM内容,而不仅仅是dat[ ]数组内容——的原因了。


C:0x0000    02000E   LJMP     STARTUP1(C:000E)
  .......

C:0x000E    787F     MOV      R0,#0x7F
   134:                 CLR     A
C:0x0010    E4       CLR      A
   135: IDATALOOP:      MOV     @R0,A
C:0x0011    F6       MOV      @R0,A
   136:                 DJNZ    R0,IDATALOOP
C:0x0012    D8FD     DJNZ     R0,IDATALOOP(C:0011)
......

C:0x0014    758131   MOV      SP(0x81),#0x31
   196:                 LJMP    ?C_START
C:0x0017    020055   LJMP     C:0055
C:0x001A    0201A6   LJMP     main(C:01A6)
C:0x001D    E4

使用特权

评论回复
18
冷漠| | 2009-11-11 10:08 | 只看该作者
欲禁止STARTUP初始化RAM,可以修改STARTUP.A51内容中的以下部分:

STARTUP1:

IF IDATALEN <> 0
                MOV     R0,#IDATALEN - 1
                CLR     A
IDATALOOP:      MOV     @R0,A
                DJNZ    R0,IDATALOOP
ENDIF

或者其他方法。

使用特权

评论回复
19
ejack| | 2009-11-11 19:43 | 只看该作者
LS的,标准51的中断向量能随便改吗?

使用特权

评论回复
20
冷漠| | 2009-11-12 09:58 | 只看该作者
LS的,标准51的中断向量是硬件确定的(前6个标准)。能改吗?

使用特权

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

本版积分规则

个人签名:了解新东西才知道自己的不足。 www.elecbench.com

67

主题

452

帖子

1

粉丝