看看反汇编吧!
while语句的: LOOP: SETB C MOV A,16H ;15H=TD3的高字节,16H=TD3的低字节 SUBB A,#050H MOV A,15H ;当TD3==45FFH时发生中断,问题就出来了! SUBB A,#046H ;从中断响应函数里回来,TD3高字节就是46H了! JC LOOP ;接上一个注释,这里CY标志就==0了,不Jump回去了!
中断的: PUSH ACC MOV TH0,#03CH MOV TL0,#0B0H INC 16H MOV 16H JNZ L_0 INC 15H L_0: POP ACC RETI 调换YH0,TL0的顺序,只能是一种巧合吧? 一个while语句对应起来相当于这么多汇编语句,其中任何时刻都有可能发生与之相关的中断,所以在中断外对相关量的引用是一个严肃的问题啊!问题的实质是:51是8位CPU,而相关的量TD3是16位的,在C里看起来 "while(字节变量 <= 字节常量)" 和 "while(整数变量 <= 整数常量)" 似乎没有本质的区别,而且,大多数情况下也确实没有本质的区别,但,在此处,"变量"在中断响应函数中发生变化,而中断外又要对这种变化作出判断,问题就出现了. 推荐的做法是:增加一个字节量TD4,主函数改成类似下面的样子: unsigned TD4 = 0; main() { ... ... //初始化等,不变 while(1) { while(TD4 == 0); TD4 = 0; //与灌溉相关的语句 } } 中断改成: void t0(void) interrupt 1 using 3 { TL0=(65536-50000)%256; TH0=(65536-50000)/256; //100mS中断时间常数(6M晶振) TD3++; if(TD3>=18000) { TD4 = 1; TD3 = 0; } } 似乎吃饱了撑的慌,为什么要增加一个变量TD4呢???注意它是字节量!在51里对字节量的增减操作和判断分别都是一个语句就搞定的,这就避免了发生所谓的"换手"的问题. (关于"换手"问题的说明: 假定做某件事可以得到4650H以上个$的报酬,但这些$按16进制规则放在两个钱包里,首先让你看零头$,你发现有FFH个$,再让你看大头$,本来是4500H个$,可赶巧在此时按事先规定的规则发生了某件事,大头变成了4600H个$,并且不让你知道或者你没有意识到同时零头$回0了!于是,你的判断就成了大头=4600H,零头=FFH,满足要求!) |