It is generally believed that the power and freedom of C language are largely reflected in its flexible use of pointers, and it is even believed that pointers are the soul of C language. Here, "usually" is said in a broad sense, because with the development of programming languages, pointers have also been controversial, and not everyone recognizes the "power" and "advantages" of pointers. In the field of single-chip microcomputers, pointers also have applications. This chapter briefly analyzes the meaning of pointers in the Keil C-51 environment.
1 Pointers and variables
A pointer is a variable. Like other variables, it is an area in RAM and can be assigned values, as shown in program ①.
#include "REG52.H"
unsigned int j;
unsigned char *p;
void main()
{
while(1)
{
j=0xabcd;
p=0xaa;
}
}
In Debug Session mode, move the mouse pointer to the position of variable "j" and "p" to display the physical address of the variable, as shown in Figure 1-1 and 1-2.
The arrow in the figure is the "first address" of the variable in RAM. Why is it the "first address"? Variables can be divided into 8-bit (single byte) and 16-bit (double byte) according to their types. The variable "j" in the program is an unsigned integer and occupies 2 bytes of physical space. In an 8-bit microcontroller, the size of a RAM storage unit is 8 bits, that is, 1 byte, so 2 storage units are required to meet the length of variable "j". So in fact, the physical address of variable "j" is "08H" and "09H". Similarly, "p (D: 0x0A)", that is, the first address of variable "p", is "0AH".
Next, we will observe the data changes in RAM by executing the program step by step. Open two Memory Windows windows, which are displayed as Memory1 and Memory2 under the Keil software. In the two windows, make the settings shown in Figures 2-1 and 2-2 respectively.
The contents of the two Addresses are: D:0x08 and D:0x0A, which are the first addresses of the variables "j" and "p". After entering, press Enter to monitor the data at the address in RAM. After setting, prepare for debugging.
In the Debug Session mode, the arrow points to the statement to be executed. Click the "Step" function button (or press F11) to run the program, as shown in Figure 3.
After clicking the "Step" button for the first time, the data in the Memory1 window is shown in Figure 4.
From the debugging results, we can see that the 08H data changes from 00H to ABH, and the 09H data changes from 00H to CDH. This change occurs because the statement j=0xabcd is executed; 08H is the high eight bits of the variable "j", storing "AB", and 09H is the low eight bits of the variable "j", storing "CD".
Click the "Step" button for the second time to execute the statement: p=0xaa; At this time, you need to observe the data in the Memory2 window, as shown in Figure 5.
From the debugging results, it can be seen that the value at 0CH changes from 00 to "AAH", and the program is consistent. It should be noted here that in the Keil C-51 compilation environment, pointer variables, regardless of whether the length is single-byte or double-byte, occupy 3 bytes. Therefore, "AAH" here is not stored at 0AH but at 0CH (0A+2) address. In
summary, pointers are actually variables, which are mapped to a storage space in RAM. The difference is that pointers occupy 3 bytes, while other variables can be set to occupy 1 byte (char), 2 bytes (int), and 4 bytes (long) of RAM as needed.
2 The role of pointers
What is the role of pointers? Let's look at the following program first:
Program ②
#include "REG52.H"
unsigned chartab1[8]={0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08};
unsigned char codetab2[8]={0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80};
unsigned char N1,N2;
void main()
{
N1=tab1[0];
N2=tab2[0];
}
Obviously, the result of program execution is N1=0x01, N2=0x10. Here, we are talking about assigning data in arrays to variables, but there is a difference. The tab1 array uses the MCU RAM space, while the tab2 array uses the MCU program storage area (ROM) space. Although the statements are the same when assigning values to variables using C language, the compilation results are different. The result of this program after compilation is shown in Figure 6.
From the compilation results, we can see that the statement N1=tab1[0] is actually direct addressing, while N2=tab2[0] is register indexing addressing. Regardless of the addressing method, the data in a physical address is taken out and used: in the tab1 array, the RAM address corresponding to tab[0] is 0x0A, the RAM address corresponding to tab[1] is 0x0B... and so on; in the tab2 array, the ROM address corresponding to tab[0] is 0x00A5, the ROM address corresponding to tab[1] is 0x00A6... and so on. Regardless of the RAM or ROM address of these arrays or variables, what the user ultimately needs is the data of the array or variable, and the pointer is to access the data through the physical address of the variable or array, that is, the array or variable data can also be accessed through the pointer. Now adjust program ② and get program ③ as follows:
#include "REG52.H"
unsigned chartab1[8]={0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08};
unsigned char code tab2[8]={0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80};
unsigned char N1,N2;
unsigned char *p;
void main()
{
unsignedchar i;
p=tab1;
for(i=0;i<8;i++,p++)
N1=*p;
p=tab2;
for(i=0;i<8;i++,p++)
N2=*p;
}
Program execution result: The 8 values in the tab1 array are assigned to N1 in turn; the 8 values in the tab2 array are assigned to N2 in turn;
After executing the Debug Session function in program ③, open the Watch Windows window, and add the variables to be monitored in the Watch1 window, here are "p" and "N1", as shown in Figure 7.
Value is the current variable value. Before the program runs, the p value is 0x00. After clicking the Step button function, execute p=tab1; the p value changes to 0x0A, as shown in Figure 8.
What is the value of 0x0A? Move the mouse to the tab1 array position to display the physical address of the array. 0x0A is the first address of the array tab1, as shown in Figure 9.
p=tab1 is to assign the first address of the tab1 array to the variable p, and execute p++ to add 1 to the address value; *p is the specific data in this physical address, so in the for loop, N1=*p is to assign the data in the tab1 array to the variable N1 in turn. It can be seen that the pointer is a variable that points to a certain address.
So how does the pointer "get" the data in a certain address? The following is a demonstration using the N1=*p statement. The assembly code after N1=*p is compiled is shown in Figure 10.
The assembly code from C:0x00A0 to C:0x00A9 is N1=*p in the C program. The program first assigns the value of the variable p to the three general registers R3, R2, and R1. The program is:
MOV R3,p(0x12)
MOV R2,0x13
MOV R1,0x14
Then a sub-function is called: LCALL C?CLDPTR(C:00E4). In the C program, no sub-function is defined or used. So where does this sub-function come from? What is its function? According to the label C:00E4, the subfunction can be found. The program code is as follows:
C:0x00E4 BB0106 CJNE R3,#0x01,C:00ED
C:0x00E7 8982 MOV DPL(0x82),R1
C:0x00E9 8A83 MOV DPH(0x83),R2
C:0x00EB E0 MOVX A,@DPTR
C:0x00EC 22 RET
C:0x00ED 5002 JNC C:00F1
C:0x00EF E7 MOV A,@R1
C:0x00F0 22 RET
C:0x00F1 BBFE02 CJNE R3,#0xFE,C:00F6
C:0x00F4 E3 MOVX A,@R1
C:0x00F5 22 RET
C:0x00F6 8982 MOV DPL(0x82),R1
C:0x00F8 8A83 MOV DPH(0x83),R2
C:0x00FA E4 CLR A
C:0x00FB 93 MOVC A,@A+DPTR
C:0x00FC 22 RET
The function of this program is: first compare the value of register R3 with 0x01. When the value of R3 is greater than 0x01, compare it with 0xFE. The comparison results are as follows:
(1) When the value of R3 is equal to 0x01, execute the following program:
C:0x00E7 8982 MOV DPL(0x82),R1
C:0x00E9 8A83 MOV DPH(0x83),R2
C:0x00EB E0 MOVX A,@DPTR
C:0x00EC 22 RET
program function: read the data in the extended RAM and assign it to A, the addressing range is 0 to 65535. When the array is defined as xdata, it will jump here.
(2) When the value of R3 is less than 0x01, that is, equal to 0x00, execute the following program:
C:0x00EF E7 MOV A,@R1
C:0x00F0 22 RET
program function: read the data in the 256-byte RAM inside the microcontroller and assign it to A, the addressing range is 0 to 255. When the array is defined as data or idata, it will jump here. When the N1=*p statement is executed, it jumps to itself and reads the data in the internal RAM address.
(3) When the value of R3 is not equal to 0x00 or 0x01, it jumps to C:0x00F1 through the JNC instruction and starts to compare with 0xFE. When the value of R3 is equal to 0xFE, execute the following program:
C:0x00F4 E3 MOVX A,@R1
C:0x00F5 22 RET
Program function: Read the data in the external RAM of the microcontroller and assign it to A. The addressing range is 0 to 255. When the array is defined with pdata, it will jump here. Usually, the 8051 microcontroller does not use pdata to define variables or arrays.
(4) When the value of R3 is not equal to 0xFE, that is, when the value of R3 is equal to 0xFF, jump to C:0x00F6 and execute the following program:
C:0x00F6 8982 MOV DPL(0x82),R1
C:0x00F8 8A83 MOV DPH(0x83),R2
C:0x00FA E4 CLR A
C:0x00FB 93 MOVC A,@A+DPTR
C:0x00FC 22 RET
Program function: read the data in the MCU's internal ROM and assign it to A, with an addressing range of 0 to 65535. When the array is defined with code, such as in program ③, the tab2 array is defined with code, after executing p=tab2, the value of R3 is assigned to 0xFF, and when the N2=*p statement is executed, it jumps to itself and reads the data in the internal ROM address.
It can be seen that the role of the sub-function "C?CLDPTR" is to read the data at a certain address using different addressing methods according to the storage space where the data is located. R3 is used to determine the addressing method. The corresponding relationship between the value of R3 and the corresponding addressing method is:
1. When the value of R3 is equal to 0x00, the on-chip RAM is indirectly addressed; at this time, the data is defined by dataidata.
2. When the value of R3 is equal to 0x01, the off-chip RAM (extended RAM) is indirectly addressed; at this time, the data is defined by xdata.
3. When the value of R3 is equal to 0xFE, the lower 246 bytes of the off-chip RAM (extended RAM) are indirectly addressed; at this time, the data is defined by pdata
. 4. When the value of R3 is equal to 0xFF, the storage memory (ROM) is indexed and addressed; at this time, the data is defined by code.
3.
The values of the pointer structures R3, R2, and R1 are the values in the addresses 0x12, 0x13, and 0x14 in the RAM, that is, the RAM address mapped by the variable p. In an 8-bit microcontroller, no matter what addressing mode is used, the maximum addressing range is 2 bytes (0 to 65535). Why does the pointer *p occupy 3 bytes of RAM space? The following program ④ explains.
Previous article:MCU + DC motor speed control program + Proteus simulation circuit
Next article:Detailed explanation of 51 single chip microcomputer controlling stepper motor
Recommended ReadingLatest update time:2024-11-16 14:24
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
- STM32F103 project of LPS33HW
- [#Ren Zhengfei responds to hot topics#: We cannot narrowly think that loving Huawei means loving Huawei phones]
- Here is the camera information on the national competition list
- RF Components Test Technology Seminar for 5G - You are invited to attend!
- Has anyone designed this power supply?
- Network Control of ROS Melodic
- Let’s take a look at how this overvoltage protection circuit can be optimized?
- Inverter and Motor Control
- 【ST NUCLEO-H743ZI Review】(2) First experience with Ethernet testing
- Disassembling a common fire emergency light