×
单片机 > 单片机程序设计 > 详情

对“C51语言应用编程的若干问题”

发布时间:2020-08-24 发布时间:
|
1 对C51中定时/计数器赋初值算法的补充

   《力源电子工程》1999年第3期《C51语言应用编程的若干问题》一文的例3中,用下述方法为T0赋初值,使T0在启动后满1000个机器周期时产生中断申请:

 

TMOD = 0X01
/*T0工件在定时器方式1,为16位*/
TH0 = -(1000/256)
TL0 = -(1000%256)

 

1.1 赋初值算法问题的验证

    这种算法(以下称其为新算法)比较新颖而且方便,不同于传统的算法。但经过验算,发现这种算法有一个漏洞,会引起定时或计数的严重错误,仍以本例进行验证如下:

 

新算法:
TH0 =-(1000/256)
  =-(3)
  = 0XFD

 

TL0

=-(1000%256)
  =-(232)
  = 0X18
传统算法:
2^16 – 1000 = 64536 = 0XFC18
即: TH0 = 0XFC
  TL0 = 0X18
两种算法得出的TH0值相差1。
若使T0在启动后1024个机器周期时产生中断申请。
新算法:
TH0 =-(1024/256)
  =-(4)
  = 0XFC
TL0 =-(1024%256)
  =-(0)
  = 0X00
传统算法:
2^16 – 1024 = 64512 = 0XFC00
即: TH0 = 0XFC
  TL0 = 0X00

 

则两种算法得出的值完全相同。

    经观察发现,当TL0 = 0X00 时,新算法得出的结果是正确的,否则,必须将新算法得出的TH0的值减去1,才能得出正确的结果。

    在所需机器周期数大于256时,这种错误将使中断提早到达256个机器周期;

    在所需机器周期数小于256时,TH0应为0XFF,新算法得出TH0=0X00,将会使中断迟到(0XFF-0X00)* 256=65280个机器周期。

    在所需机器周期数等于0时最甚(当然,在实际编程中不会出现这种情况,但为严谨起见,对其进行论述),中断将会迟到65536个机器周期。

证明:

    为方便理解,仍以16位的定时/计数器为例,对13位的定时/计数器仍可以用下述方法进行证明(见1.3适用范围一节)。

    设X表示定时/计数所需的机器周期数

    设A = X/256(本文中X/256均指X除以256舍尾取整);B = X%256。

    1. 当X>256时

    新算法的计算过程中

TH0 =-(X/256),实际上是TH0 = 256-(X/256),因为TH0是8位长度,它的值不超过255。

TL0 =-(X%256)是同样道理。

则新算法的计算过程可表示为:

TH0TL0 =(256-X/256)* 256 +(256-X%256)

      =(256-A)* 256 +(256-B)

      = 65536-256A +(256-B)    (1)

    式(1)中(256 – B)即 TL0 的值。

    传统算法的计算过程可表示为:

TH0 TL0 = 65536-X

        = 65536-[(X/256)* 256 + X%256]

        = 65536-256A-B   (2)

可以看出,新算法确实比传统算法的正确值多了256,也就是说,TH0的值应减去1,只有当式(2)中B=0时,在新算法中则:TL0 =-(B)=0,即式(1)中的(256-B)=0,此时式(2)与式(1)才相等。

    2. 当X<256时(A=0)

    新算法的计算过程可表示为:

TH0TL0 =-(X/256) * 256 + 256-X%256

        = 256-B     (3)

    传统算法的计算过程可表示为:

TH0TL0 = 65536-B      (4)

    新算法的结果比传统算法结果小65280,若将其TH0减去1变为0XFF,则为正确结果。

    3. 特例,当X=0时(A=B=0)

    新算法的计算结果为:

TH0TL0 = 0X0000      (5)

    传统算法的计算结果为:

TH0TL0 = 0X10000(实际上不可能) (6)

    两者相差65536。

1.2 产生问题的原因分析

    (1) 分析产生这个问题的原因,可先从定时/计数器的工作过程入手。

    新算法中

TH0 =-(X / 256)

TL0 =-(X % 256)

    其主观意图是在TH0中装入0X100H(即256)减去X/256的整数部分得出的差ΔTH0,使TH0控制计数ΔTH0* 256个机器周期T(或输入ΔTH0* 256个计数脉冲),TL0也同理;然而当TL0≠0时,定时/计数器在启动后的(256-TL0)个机器周期T后即向TH0进位。按前面所说的主观意图来理解,则是在TH0中记录下“已计满256个机器周期T的时间或256个输入脉冲”的信息。也就是说:TL0所设定的(256-TL0)个机器周期T,错误地使TH0(应记录整数个256T)“跳数”(加1),将使定时/计数器产生非预期的中断申请。

    所以当TL0≠0时新算法得出的TH0值应减去1,则可以避免此错误的发生。程序应以如下形式:

TH0 =-(X / 256)

TL0 =-(X % 256)

if (TL0<>0) TH0- -;

    相反,当TL0=0时,TL0计数满后向TH0进位正是新算法的本意,所以不会发生定时/计数错误。

    上面分析了当X>256时的情况(A>0),当X<256时,A=0,新算法得出TH0=0,显而易见应为TH0=0XFF。

    (2) 简单地说:新算法是把传统算法的0X10000-hhll(hhll=X)当作(0X100-hh)赋给TH0,(0X100-ll)赋给TL0来计算,当ll=0时,(0X100-ll)=0X100,没用向0X100的最高位“1”即TH0借位;当ll≠0时,要发生借位,传统算法中有这一过程,而新算法则丢失了这个借位,所以会在TH0中多出1来。

    之所以要从不同角度进行分析,是因为在实际编程中,我们可能会从不同角度出发确定算法,经过上述分析,可以避免类似失误的发生。

1.3 适用范围

    当定时/计数器工作在模式0时,将算法中的256替换为32,使用如下语句:

TH0 =-(X/32)

TL0 =(-(X%32))& 0X1F

if(TL0<>0) TH0--;

    则同样适用上述结论。文中以定时/计数器0 的定时器方式为例,但对定时/计数器1以及它们工作在计数器方式时也是适用的。

2 对C51条件编译语句#if…用法的订正

  《力源电子工程》1999年3期《C51语言应用编程的若干问题》一文中有下述宏定义与条件编译例子(例1):

 

#define flag 1
  #ifdef flag==1
   #define fosc 6M
    delay=10;
  #elif flag==0
 

 

#define fosc 8M

  delay=12;
  #else
#define fosc 12M
    delay=20;
  #endif
  main()
    {
    for(I=0;I
    }

 

    经实际运行,发现“#ifdef flag==1”一句似有不妥,为叙述方便起见,设有如下情形。

    1. 情形1

    #ifdef 标识符

    该条件编译语句当并且仅当 “标识符” 曾被“#define”语句定义过(如果有“# undef 标识符”语句则在其前面)时为TRUE,即使如下形式也是如此:

    #ifdef 标识符 == 常量 亦即:#ifdef 常量表达式。

    2. 情形2

    #if 标识符 == 常量 亦即:#if 常量表达式

    该条件编译语句当并且仅当 “标识符 == 常

    量”为TRUE时,为TRUE。

    所以在上述例子中“#ifdef flag == 1”的值将永远为TRUE,不论“flag == 1”是否为TRUE。

    根据程序目的可知,这一句应为:

“#if flag ==1”。

    另外,在Franklin C51 V3.20编译系统目录OMF51EXAMPLESDCLOCK.C 中有如下一段:

#ifdef CPU==8051

#define SECOND (4000/(12/FREQ))

#else

#define SECOND (200/(12/FREQ))

#endif

    在此段前没有出现对“CPU”的定义,实际上, #ifdef CPU==8051

一句是不合理的。其值等于 #ifdef CPU

而非

(#ifdef CPU) && (#if CPU==8051)

    特别指出,在参考文献2第128页的例子中,也出现了

#ifdef CPU==8051,这一语句。

    上述结论作者经过Franklin C51 V3.20编译验证。

参 考 文 献

1 张毅刚, 修林成, 胡振江. MCS-51单片机应用设计. 哈尔滨:哈尔滨工业大学出版社, 1990

2 徐爱钧, 彭秀华. 单片机高级语言C51应用程序设计. 北京:电子工业出版社, 1998


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
51单片机CO2检测显示程序解析