Research on 8051 Series MCU Software Precision Delay (Part 2)

Publisher:Blissful567Latest update time:2024-07-23 Source: cnblogs Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

As we can see in the previous article, using a for loop to delay in the DelayX10us() function will produce a fixed error of 10 machine cycles, of which X passing the value, calling the function, and the sub-function returning a total of 5 machine cycles, which is a fixed error for any call to a sub-function with parameters. The for loop determines that x>0 and jumps to produce an additional error of 5 machine cycles.


improve

According to the content mentioned in "Designing Accurate Delay Functions in the Microcontroller Keil C Development Environment", the for loop can be changed to while(--x) to eliminate the extra 5 machine cycle errors caused by the for loop.


Note: You should use while(--x) so that the corresponding generated assembly statement is DJNZ. If you use while(x--), several extra instructions will be generated, making this delay function inaccurate.


The modified procedure is as follows:


//Inaccurate delay 10*X us, fixed error 5us

//@12.000MHz 12T

void DelayX10us(unsigned char x)

{

unsigned char i;

do

{

_nop_();

i=3;

while(--i);

} while (--x);

}


Disassembly analysis


As before, using the optimization level 8, the disassembled code is as follows:

Calculate the delay time:

x Fixed delay Loop Delay total
1 5 (1+1+2*3+2)*1 15
10 5 (1+1+2*3+2)*10 105
100 5 (1+1+2*3+2)*100 1005







It can be seen that the error has been reduced to 5us.


Official millisecond-level delay analysis

For the improved DelayX10us function, the maximum value of X is 255, so its maximum delay is 255*10=2550us=2.55ms. What if you want to get a longer delay? It should be noted here that you cannot simply change X to unsigned int to get a longer delay, because 8051 is an 8-bit microcontroller. For the 16-bit int type, it needs to be divided into high 8 bits and low 8 bits for operation, and the sentence "while(--x);" will not only take 2 machine cycles. So we redefine a millisecond delay function. The official STC delay 1ms program is as follows:


//@12.000MHz, STC official version

void Delay1ms() //No machine cycle is assigned here

{

unsigned char i, j;


i = 2;

j = 239; //Please note the position of j assignment

do

{

while (--j);

} while (--i);

}


According to the previous method, the number of delay cycles t = function call LCALL + ij assignment + loop + return RET = 2 + 1+1+(239*2+2)*2 +2= 966 [Thanks to group member Smiles for pointing out the 2 omitted assignment cycles]. It is quite different from the expected 1000 machine cycles. Why?


It should be noted that the variable j is assigned a value outside the loop. When the outer loop is executed for the second time (i=1), j will not be assigned a value of 239, so 239*2 cannot be used for calculation. Here, a trick of overflow is used. The simple analysis process is as follows:


After i=2, j=239 is assigned (2 machine cycles), it enters the inner loop and executes "while(--j);" 239 times, j=0, and then exits. From the previous analysis, we know that the assembly code of "while(--j);" is DJNZ instruction, which is a 2-cycle instruction, and the number of cycles is t1=2+239*2.


Then it executes to the outer loop "while(--i);", 2 machine cycles, i=1, DJNZ instruction jumps to the inner loop to continue execution, cycle number t2=2.


After entering the inner loop again, j=0. The DJNZ command first decrements the register by 1 and then determines whether it is 0. Therefore, after executing --j, j overflows to 0xFF (decimal 255), which is not equal to 0. The statement "while(--j);" continues to execute until j is decremented to 0 again and then jumps out. The number of cycles t3=256*2.


Go to the outer loop again, "while(--i);", i=0, jump to the end of the function and prepare to return. Cycle number t4=2.


The number of function call and return cycles is t5 = 2 + 2. There is no parameter passing when calling the function, so there is no assignment cycle.


The total number of cycles t=t1+t2+t3+t4+t5=2+239*2+2+256*2+2+4=1000. Just right!


Millisecond delay function transformation

Now we transform the official function that can only delay 1ms into one that can delay multiple ms. According to the previous method, we put a do..while loop in the delay code.


do


{


i = 2; j = 239;


do { while (--j); }


while (--i); }


while (--x);


At this time, the number of delayed machine cycles = 1+2+(2+239*2+2+256*2+2+2)*X+2=998*X+5, and the multiple is not 1000, so there is an error. When x=1, t=1003; when x=10, t=9985; when x=100, t=99805, there is an error of nearly 200us, so we change the machine cycle in the brackets to 1000, and just change j=240, so that the total number of cycles T=1+2+(2+240*2+2+256*2+2+2)*X+2=1000*X+5, with a fixed error of 5us. The modified code is as follows:


/**

* Crystal oscillator 12MHz, delay 1*x ms in 12T mode, fixed error 5us.

*/

void DelayX1ms(unsigned char x)

{

unsigned char i, j;

do

{

i = 2;

j = 240;

do

{

while (--j);

} while (--i);

} while (--x);

}


By following this model, you can write any delay program with a fixed error of 5us.


In addition, for a delay of a few microseconds, it is recommended to use _nop_() delay. Considering portability, it is not recommended to write multiple _nop_() directly in the program to delay. Write all delay functions in Delay.h and Delay.c files, and the rest of the program will all call this library. If you need to change it later, such as changing to STC's 1T microcontroller, the delay needs to be modified, and you only need to change these two files.


Finally, attached is the delay function library I am using. The fixed error of all X times delay = 5us.


#ifndef __DELAY_H__

#define __DELAY_H__


typedef unsigned char UINT8


//Define default settings: crystal 12MHz, mode 12T

#define FSOC_12M_MOD_12T

/**

* Crystal oscillator 12MHz, delay in 12T mode.

*/

#ifdef FSOC_12M_MOD_12T

#define NOP() _nop_()

#define Delay1us() NOP()

#define Delay2us() NOP();NOP()

#define Delay5us() NOP();NOP();NOP();NOP();NOP()

#endif


void DelayX10us(UINT8 X);

void DelayX1ms(UINT8 X);

void DelayX10ms(UINT8 X);

void DelayX1s(UINT8 X);


#endif


/**

*************************************************** **********

****** Copyright(C), 2010-2016, NULL Co.,Ltd ******

*************************************************** **********


*@Tittle: General delay function

*@Version : v1.1

*@Author : Liy

*@Dat: 2016-08-10 15:03:15

*@Desctription: Delay function library

*@History:

* #v1.1 2016-08-10 15:03:41

* 1. Delete the fixed delay function and only keep the X times delay;

* 2. Optimize the time of X-times delay function, and control the error of all X-times delay functions to 5us.

* #v1.0 2016-08-03 16:44:18

* 1. Complete the commonly used delay functions in 12MHz and 12T modes


*************************************************** **********

*************************************************** **********

*/



#include "Delay.h"


/**

* Crystal oscillator 12MHz, delay in 12T mode

*/

#ifdef FSOC_12M_MOD_12T

/**

* Crystal oscillator 12MHz, delay 10*X us in 12T mode, fixed error 5us.

* X maximum value 255

*/

void DelayX10us(UINT8 X)

{

UINT8 i;

do

{

_nop_();

i = 3;

while (--i);

} while (--X);

}


/**

* Crystal oscillator 12MHz, delay 1*X ms in 12T mode, fixed error 5us.

* X maximum value 255

*/

void DelayX1ms(UINT8 X)

{

UINT8 i, j;

do

{

i = 2;

j = 240;

do

{

while (--j);

} while (--i);

} while (--X);

}


/**

* Crystal oscillator 12MHz, delay 10*X ms in 12T mode, fixed error 5us.

* Number of cycles N=((2+(114*2+2)+(256*2+2)*19+2))*X+5

* X maximum value 255

*/

void DelayX10ms(UINT8 X)

{

UINT8 i, j;

do

{

i = 20;

j = 114;

do

{

while (--j);

} while (--i);

} while (--X);

}


/**

* Crystal oscillator 12MHz, delay 10*X s in 12T mode, fixed error 5us.

* Number of cycles N=(1+3+(((123*2+2)*1+(256*2+2)*153) +2 ) + ((256*2+2)*256+2)*7+2)*X+5

* X maximum value 255

*/

void DelayX1s(UINT8 X)

{

UINT8 i, j, k;


do

{

NOP();

i = 8;

j = 154;

k = 123;

do

{

do

{

while (--k);

} while (--j);

} while (--i);

} while (--X);

}


#endif


OK, now that I have a brief understanding of assembly and the software delay is basically accurate, that’s it.


Reference address:Research on 8051 Series MCU Software Precision Delay (Part 2)

Previous article:Universal infrared remote control signal analysis program based on STC12 series microcontroller (I)
Next article:Research on 8051 Series MCU Software Precision Delay (Part 1)

Latest Microcontroller Articles
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号