introduction
Using C language to program MCS51 series microcontrollers is an inevitable trend in the development and application of microcontrollers. Keil's C51 compiler supports the classic 8051 and 8051 derivatives, commonly known as Cx51. It should be said that Cx51 is an extension of C language on MCS51 microcontrollers. It has both the common features of C language and its own characteristics. This article introduces the calculation method of stack when programming Cx51 .
1 Stack overflow problem
The MCS51 series of microcontrollers set the stack in the on-chip RAM. Due to the limited on-chip RAM resources, the range of the stack area is also limited. If the stack area is too large, it will reduce the storage space for other data, and if it is too small, it is easy to overflow. The so-called stack overflow means that when the stack area is full, a new stack push operation is required. At this time, the pushed content has to be stored in the special function register (SFR) of the non-stack area or the data area outside the stack. The content of the special function register affects the state of the system, and the content of the data area is easily modified by the program. In this way, when the stack pop operation (such as subroutine return) is performed later, the content has changed, and the program is messed up. Therefore, the stack area must be enough, and it is better to be larger. To prevent stack overflow in Cx51 programming, two problems must be solved: first, accurately calculate the stack size allocated by the system to the user, assuming it is M; second, accurately calculate the stack size required by the user, assuming it is N. It is required that M≥N. The following analyzes these two problems respectively.
2 Computing System
In Cx51 programming, because dynamic local variables are resident in memory, they are actually equivalent to local static variables, and the space is not released even at the end of the function call (this is different from the standard C language). The Cx51 compiler stores all variables in the on-chip and off-chip RAM according to the user's settings. After the space is allocated for the on-chip variables, the remaining space is used as stack space, which is the maximum possible stack space. Of course, because Cx51 is a C language that can access registers (special function registers), SP can be accessed in the program to set the stack space smaller. However, generally no one does this. This article only discusses variables placed in the on-chip RAM. We divide variables into two cases:
① Local variables used as function parameters and function return values. Such variables should be stored in register groups as much as possible. For the convenience of discussion, it is assumed that register group 0 is used uniformly, and the specific addresses are 0x00~0x07. A maximum of 3 parameters can be passed. If the number of parameters is large, the extra parameters are stored in the memory (address after 0x08). Here, it is assumed that the number of parameters of each function is no more than 3.
② The global variables we define in the program, as well as local variables that are not used as function parameters and function return values. The above two types of variables are stored after address 0x08 in the memory. After storage, the stack pointer SP points to the last byte of the on-chip RAM where the variable is allocated. Because the stack of the MCS51 microcontroller is a full-increment stack and the stack width is 8 bits, when a push operation is required, the stack pointer is first increased by 1, and then the valid content is pushed into the stack. With the above rules, the stack space allocated to the user by the system can be accurately calculated. Taking the function of finding the greatest common divisor and the least common multiple of two numbers as an example, the code is as follows:
#include
unsigned char max(unsigned char a, unsigned char b);
unsigned char min(unsigned char a, unsigned char b);
unsigned char M;
void main (void) {
unsigned char n;
M = max(12, 9);
n = min(12, 9);
}
unsigned char max(unsigned char a, unsigned char b){
while(a != b) {
if(a > b)
a = a - b;
else
b = b - a;
}
return a;
}
unsigned char min(unsigned char a, unsigned char b){
unsigned char k;
k = a*b/M;
return k;
}
The resource allocation in this program is as follows: a global variable M (unsigned character type) stores the greatest common divisor; a local variable n (unsigned character type) is defined in the main function to store the least common multiple; the function unsigned char max (unsigned char a, unsigned char b) for finding the greatest common divisor has two parameters a and b; the function unsigned char min (unsigned char a, unsigned char b) for finding the least common multiple has two parameters a and b, and a variable k is defined to store the return value of the function. The space allocated by the system to the variables can be calculated from this. The parameters and return values of the function are stored in the working register group, so they do not occupy the space after the address 0x08. The system only allocates storage space to the variables M and n. These two variables occupy two bytes (addresses 0x08 and 0x09), so the stack pointer SP should point to 0x09. The system resource usage of the generated code after the Cx51 system is compiled is as follows: the address of the global variable M is 0x08, the address of n is 0x09, and the value of SP is 0x09. This is consistent with our calculation results.
3 Calculate the stack size required by the user
How big should the stack area be to be considered sufficient? In Cx51 programming, the size of the stack required by the user can be calculated from the number of nesting levels of ordinary subroutines and interrupt subroutines. The call of ordinary subroutines is relatively simple. Each time it is called, the return address of the function is saved in the stack, and this address occupies two bytes. When functions are nested, starting from the innermost subroutine, the total number of bytes required for the stack is the number of nesting levels multiplied by 2. The stack requirements of interrupt subroutines are divided into two cases:
① The interrupt subroutine uses the register group before the interrupt occurs. When an interrupt occurs, 2 bytes are required to save the return address of the interrupt subroutine. After the interrupt occurs, the system automatically performs the following operations in the interrupt subroutine: ACC, B, DPH, DPL, PSW, R0~R7, a total of 13 registers, are pushed onto the stack. Including the interrupt return address, the interrupt stack requires 15 bytes.
② The interrupt subroutine uses its own dedicated register group. In this case, the contents of R0~R7 do not need to be saved, which can reduce the stack requirements. Other contents still need to be pushed on the stack for protection. When an interrupt occurs, 2 bytes are required to save the return address of the interrupt subroutine. After the interrupt occurs, the system will automatically perform the following operations in the interrupt subroutine: ACC, B, DPH, DPL, PSW, a total of 5 registers are pushed on the stack. Adding the interrupt return address, the stack requirement is 7 bytes. However, it should be noted that if a sub-function is called in the interrupt subroutine, and the function requires parameters and return values, the called sub-function and the interrupt subroutine must use the same register group, otherwise unpredictable consequences will occur. Take a temperature test system as an example. The system uses 8051 as the processor. After the A/D conversion is completed, the temperature signal is reminded to receive and process the microcontroller through external interrupt 0. Timing interrupt 0 is used as a monitoring program, and the interrupt cycle is 20 ms. The temperature signal can be measured automatically (once per second) or manually (measured after pressing the measurement key). These two measurement methods can be switched by the control key. The nesting of interrupt subroutines and common subfunctions is as follows: the display subroutine is called in the timer interrupt program, and there is no function call inside the external interrupt 0. Part of the program is as follows:
void int0(void) interrupt 0 using 1 {
Read conversion data;
Data processing;
}
void time0 (void) interrupt 1 {
The count value is reloaded;
Read key;
Key processing;
leddisp(adat); //display
}
void main (void) {
Initialization of relevant data and self-check of digital display;
External interrupt and timer initialization settings;
MCU sleep;
}
void leddisp(unsigned char *pt) {
Use serial port working mode 0 to send display data, and display it statically after conversion by 74LS164;
}
Next, we analyze the maximum stack requirement of this program. Assume that when timer 0 is interrupted, the display function void leddisp(unsigned char *pt) is called. When the display function is called, the A/D conversion ends and the external interrupt 0 interrupt occurs. At this time, the maximum stack requirement of the program should be: timer 0 (15 bytes) + display function (2 bytes) + external interrupt 0 (7 bytes) = 24 bytes.
Conclusion
By accurately calculating the stack space allocated to the user by the compiler system and the user's own maximum stack requirement, not only can the stack overflow problem be fundamentally solved, but also the relatively tight resources of the microcontroller can be well arranged. In addition, by storing an appropriate amount of local variables in the on-chip memory, the execution speed of the software can be effectively improved.
Previous article:Design of CAN bus signal acquisition node based on P87C591
Next article:Construction of embedded remote power grid monitoring system based on SX52BD microcontroller
- Popular Resources
- Popular amplifiers
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- New real-time microcontroller system from Texas Instruments enables smarter processing in automotive and industrial applications
- Device thermal coupling and heat dissipation solutions on PCB
- [Mil MYS-8MMX] Mil MYS-8MMQ6-8E2D-180-C Unpacking Report 3——Network
- Some considerations for DSP hardware design
- The significance of weld seam tracking sensors in the field of welding
- TI's new optical stage lighting DLP chipset is said to provide up to 15,000 lumens of monochrome light
- Memory alignment processing for ARM processors
- Last day for pre-registration! In-depth analysis of Infineon's star product IGBT7, live broadcast to understand the device operation and load process
- [Rawpixel RVB2601 development board trial experience] Use FreeRTOS with caution
- Brushless motor drive control hardware circuit sharing
- Share: [Skills Competition Notes 01] Zigbee point-to-point button control program development