bit
It is the address of a bit in the 20H .. 2FH area of the internal data memory space, or a bit address of an 8051 bit-addressable SFR.
code
is a code address between 0000H .. 0FFFFH.
data
is a data memory address between 0 and 127, or a special function register (SFR) address in the range 128 .. 255.
idata
is an idata memory address in the range of 0 to 255.
xdata is an xdata memory address in the range 0 to 65535.
Detailed explanation of the relationship between pointer types and storage areas
1. Relationship between storage type and storage area
data ---> addressable on-chip ram
bdata ---> bit-addressable on-chip ram
idata ---> addressable on-chip ram, allows access to all internal ram
pdata ---> paged addressable off-chip ram (MOVX @R0) (256 BYTE/page)
xdata ---> addressable off-chip ram (64k address range)
code ---> program storage area (64k address range), corresponding to MOVC @DPTR
2. Relationship between pointer type and storage area
When declaring a variable, you can specify the storage type of the variable, such as:
uchar data x and data uchar x are equivalent, both of which allocate a one-byte variable in the internal RAM area.
Similarly, for the declaration of pointer variables, the corresponding storage area type keyword is used because the storage location of the pointer variable itself and the storage area pointed to by the pointer are different
. For example:
uchar xdata * data pstr
It means to allocate a pointer variable in the internal RAM area (the function of the data keyword after the "*"), and this pointer itself points to the xdata area (the function of the xdata keyword before the "*").
It may be a little difficult to understand and remember when you first learn C51. It doesn't matter. We can immediately see what happens when using different keywords before and after the "*" during compilation.
......
uchar xdata tmp[10]; //Open up 10 bytes of memory space in the external RAM area, the address is 0x0000-0x0009 of the external RAM
......
Case 1:
uchar data * data pstr;
pstr=tmp;
First of all, I want to remind you that this code has a bug. It cannot correctly access the tmp space in this way. Why? After compiling, we see the following assembly
code:
MOV 0x08,#tmp(0x00); 0x08 is the storage address of pointer pstr
Did you see it? Originally, accessing external RAM requires 2 bytes to address 64k space, but because the data keyword (the one before the "*") is used,
it is compiled into a pointer variable pointing to internal RAM according to the KeilC compilation environment. This is also a bug caused by beginners of C51 who do not understand the keyword definitions of each storage type. Especially when
the default storage area class in the project is large, and tmp[10] is declared as uchar tmp[10], such a bug is very hidden and not easy to be discovered.
Case 2:
uchar xdata * data pstr;
pstr = tmp;
This is fine. This method of use means allocating a pointer variable in the internal RAM (the function of the data keyword after the "*"), and this pointer itself points to
the xdata area (the function of the xdata keyword before the "*"). The compiled assembly code is as follows.
MOV 0x08,#tmp(0x00); 0x08 and 0x09 are the pstr pointer variable address space allocated in the internal RAM area
MOV 0x09,#tmp(0x00)
This situation should be the most efficient way to access external RAM among all the situations introduced here, please remember it.
Case 3:
uchar xdata * xdata pstr;
pstr=tmp;
This is also true, but not as efficient as case 2. The compiled assembly code is as follows.
MOV DPTR, #0x000A ;0x000A, 0x000B are the pstr pointer variable address space allocated in the external RAM area
MOV A, #tmp(0x00)
MOV @DPTR, A
INC DPTR
MOV A, #tmp(0x00)
MOVX @DPTR, A
This method is generally used in projects where RAM resources are relatively tight and efficiency requirements are not high.
Case 4:
uchar data * xdata pstr;
pstr=tmp;
If you have read the first case in detail, you will find that this method is very similar to the first case. Yes, it has a bug just like the first case, but this time pstr is allocated
to the external RAM area. The compiled assembly code is as follows.
MOV DPTR, #0x000A; 0x000A is the address space of the pstr pointer variable allocated in the external RAM area
MOV A, #tmp(0x00)
MOVX @DPTR, A
Case 5:
uchar * data pstr;
pstr=tmp;
Everyone noticed that the keyword declaration before "*" is gone. What will happen? Write it like this! By the way, to use the title of an old song by Chyi Yu, it is "Please follow me
". Please follow me to see the compiled assembly code. Someone asked if this is not about C51? Why do we need to show us the assembly code? If you want to use C51 well, you must try to improve
the efficiency of C51 after compilation. Looking at the compiled assembly will help you become an expert in producing efficient C51 code as soon as possible. Let's look at the code!
MOV 0x08, #0X01; 0x08-0x0A is the address space of the pstr pointer variable allocated in the internal RAM area
MOV 0x09, #tmp(0x00)
MOV 0x0A, #tmp(0x00)
Note: This is a new introduction. You may wonder why the pstr pointer variable in the previous cases uses 2 bytes but only 3 bytes here
. This is an internal process of KeilC. In KeilC, a pointer variable occupies a maximum of 3 bytes. For pointers that do not declare the pointer to the storage space type,
the system compiles the code and forces a byte of pointer type discrimination value to be loaded. For the specific correspondence, please refer to the C51 User's Guide in KeilC's help.
Case 6:
uchar * pstr;
pstr=tmp;
This is the most direct and simplest pointer variable declaration, but it is also the least efficient. Again, let's say it together! The compiled assembly code is as follows.
MOV DPTR, #0x000A; 0x000A-0x000C is the pstr pointer variable address space allocated in the external RAM area
MOV A, #0x01
MOV @DPTR, A
INC DPTR
MOV DPTR, #0x000A
MOV A, #tmp(0x00)
MOV @DPTR, A
INC DPTR
MOV A, #tmp(0x00)
MOVX @DPTR, A
This situation is very similar to the combination of the 5th and 3rd situations, which not only allocates pstr in the external RAM space but also increases the resolution value of the pointer type.
To summarize: you have seen the above 6 situations, among which the most efficient is the second situation, which can correctly access the RAM area and save code, and the worst efficiency is the sixth
situation, but it does not mean that you can only use the second method. It depends on the situation. Generally speaking, the internal RAM resources of the system architecture of the 51 series are very tight. It is best
to use the internal RAM when defining local variables inside functions or program segments, and try not to declare global variables as internal RAM areas. So for global pointer variables, I recommend using the third
situation, and for local pointer variables, use the second method.
The role of startup.a51
Like assembly, the variables and arrays defined in C are initialized in startup.a51. If you define a global variable with a value, such as unsigned char data xxx="100";, then startup.a51 will have a related assignment. If there is no =100, startup.a51 will clear it to 0. (startup.a51 == variable initialization). After these initializations are completed, the SP pointer will also be set. There will be no assignment or clearing action for non-variable areas, such as the stack area.
Some people like to modify startup.a51 to satisfy their own hobbies, which is unnecessary and may be wrong. For example, when power-off protection is performed, you want to save some variables, but modifying startup.a51 to achieve this is a stupid method. In fact, you only need to use the characteristics of the non-variable area and define a pointer variable to point to the lower part of the stack: 0xff. Why do you still need to modify it? It can be said that you don't need to modify startup.a51 at any time, if you understand its characteristics
8051 unique memory types
code
program memory read with MOVC @A+DPTR
data
internal data memory that can be directly accessed
idata
internal data memory accessed with MOV @Rn
bdata
bit addressable internal memory
xdata
external data memory accessed with MOVX @DPTR
pdata
external data memory accessed with MOVX @Rn
Special data types
bit
general bit variable
sbit
absolute addressing bit variable
Syntax
sbit
my_flag
=
location;
(location range from 0x00 ~ 0x7F)
Example
sbit
EA =
0xAF;
or bit variable declared with bdata
char
bdata
my_flags;
sbit
flag0 =
my_flags ^ 0;
(Note that static cannot be added before sbit)
sfr
Special Function Register
Syntax
sfr
my_sfr
=
location;
(location range from 0x80 ~ 0xFF)
Example
sfr
P0
=
0x80;
Specify the absolute address of the variable
In a single module, the following syntax can be used to declare
[memory_space]
type
variable_name
_at_
location
Example
pdata
char
my_pdata
_at_
0x80;
If the variable must be used by multiple modules (Global Variable),
it is more convenient to define it in the header file as an abstract pointer.
#define
variable_name
*((data_type *)
location)
Example
#define
my_pdata
*((char pdata *)
0x80)
(Note the order of char and pdata)
ABSACC.H provides the following convenient macro definitions.
#define CBYTE ((unsigned char volatile code *) 0)
#define DBYTE ((unsigned char volatile data *) 0)
#define PBYTE ((unsigned char volatile pdata *) 0)
#define XBYTE ((unsigned char volatile xdata *) 0)
#define CWORD ((unsigned int volatile code *) 0)
#define DWORD ((unsigned int volatile data *) 0)
#define PWORD ((unsigned int volatile pdata *) 0)
#define XWORD ((unsigned int volatile xdata *) 0)
Hidden initialization program
The first program module executed by 80C51 after power reset (Power On Reset) is not the user's main program
main(), but a program module called startup.a51 hidden in the KEIL-C51 standard link library.
The main task of startup.a51 is to clear the memory blocks including idata, xdata, and pdata to 0, and
initialize the recursive pointer. Then startup.a51 is still executed by a
program module called init.a51 hidden in the KEIL-C51 standard link library. The main task of init.a51 is to initialize
variables with non-zero initial values.
After completing the above initialization program, the control of 80C51 will be handed over to main() to start executing the user's program.
#define XBYTE ((unsigned char volatile xdata *) 0)
defines XBYTE as a pointer to the unsigned char data type in the xdata address space, and the pointer value is 0.
In this way, you can directly use XBYTE[0xnnnn] or *(XBYTE+0xnnnn) to access external RAM
Previous article:51 MCU serial communication principle explanation
Next article:CS5532 C51 Driver
- Popular Resources
- Popular amplifiers
- Learn ARM development(16)
- Learn ARM development(17)
- Learn ARM development(18)
- Embedded system debugging simulation tool
- A small question that has been bothering me recently has finally been solved~~
- Learn ARM development (1)
- Learn ARM development (2)
- Learn ARM development (4)
- Learn ARM development (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- CGD and Qorvo to jointly revolutionize motor control solutions
- CGD and Qorvo to jointly revolutionize motor control solutions
- Keysight Technologies FieldFox handheld analyzer with VDI spread spectrum module to achieve millimeter wave analysis function
- Infineon's PASCO2V15 XENSIV PAS CO2 5V Sensor Now Available at Mouser for Accurate CO2 Level Measurement
- Advanced gameplay, Harting takes your PCB board connection to a new level!
- Advanced gameplay, Harting takes your PCB board connection to a new level!
- A new chapter in Great Wall Motors R&D: solid-state battery technology leads the future
- Naxin Micro provides full-scenario GaN driver IC solutions
- Interpreting Huawei’s new solid-state battery patent, will it challenge CATL in 2030?
- Are pure electric/plug-in hybrid vehicles going crazy? A Chinese company has launched the world's first -40℃ dischargeable hybrid battery that is not afraid of cold
- Domestic operating systems are on the rise. Is this Linux your cup of tea?
- The difference between polymer tantalum capacitors and ordinary tantalum capacitors
- GD32L233 GCC startup file and link file sharing
- MSP430 MCU Example 21 - Timer B generates 8-channel periodic signals
- Switching power supply waveform
- MSP430FR2355 LaunchPad Development Kit
- 6 Fusion Positioning Technologies for Wireless Communication Applications in IoT
- PlainDAQ data logger based on Raspberry Pi Pico
- EEWORLD University----Live Replay: Microchip Security Series 21 - Secure Boot and Message Authentication for CAN FD in ADAS and IVI Systems Using TA100-VAO
- FAQ: September 6th TTI&TE "The development and latest application of sensors in industrial motors" live broadcast room Q&A