dATa: Fixed to the first 128 RAM addresses from 0x00 to 0x7F, can be directly read and written using ACC, fastest speed, and generates the smallest code. iDATa: Fixed to the first 256 RAM addresses from 0x00 to 0xFF, where the first 128 are identical to dATa, but accessed in a different way. iDATa is accessed similarly to pointers in C. The assembly statement is: mov ACC,@Rx. (Unimportant addition: iDATa performs well with pointer access in C). xdATa: External extended RAM, generally refers to external space from 0x0000 to 0xFFFF, accessed using DPTR. pdATa: The lower 256 bytes of external extended RAM, read and written when the address appears in A0-A7, using movx ACC,@Rx. This is quite special, and C51 seems to have a bug regarding this, so it is recommended to use it sparingly. However, it has its advantages; the specific usage belongs to intermediate issues, which will not be discussed here. The role of startup.a51 is similar to assembly, where the initialization of variables and arrays defined in C is carried out in startup.a51. If you define global variables with values, like unsigned char dATa xxx=”100″, then startup.a51 will have related assignments. If there is no =100, startup.a51 will clear it to 0. (startup.a51 == variable initialization). After these initializations, the SP pointer will also be set. For non-variable areas, such as the stack area, there will be no assignment or zeroing action. Some people like to modify startup.a51 to satisfy their own assumptions, which is unnecessary and may lead to errors. For example, when wanting to preserve some variables during power failure protection, modifying startup.a51 to achieve this is a clumsy method; in reality, you can simply utilize the characteristics of non-variable areas by defining a pointer variable pointing to the lower part of the stack: at 0xFF. Why modify it? It can be said that at any time, there is no need to modify startup.a51 if you understand its characteristics. bit is the address of a bit in the internal data storage space from 20H to 2FH, which appears in byte form after 20H in DATA, and can refer to each other. Additionally, with the SFRs that can be addressed by 8051, but it has just been tested that only 00H to 7FH is effective, meaning when data changes, the color turns red; from 80H to FFH is not a bit-addressable area, but special registers that can be bit-addressed, of course, there will be a response if those 11 addressable bits are involved. After reset, the content of the program counter PC is 0000H, and the values of each internal RAM unit are uncertain. The reset values of each functional register are as follows: the reset value of the stack pointer SP is 07H, the reset value of the accumulator ACC and register B is 00H, the reset value of the data pointer DPTR is 0000H, while the reset values of ports P0, P1, P2, P3 are 0FFH. Other SFRs such as PSW, TCON, TMOD, TL0, TH0, TL1, TH1 also reset to 00H. wave contains the low 128 bytes and high 128 bytes (0-7FH), with the low 128 bytes being the on-chip RAM area, and the high 128 bytes (80-FFH) being SFRs. bit is located in the low 128 bytes from 20H to 2FH, that is, the data area from 20H to 2FH. code is an address range for code from 0000H to 0FFFFH. I used ORG 5000H TAB: DB 22H,3BH,43H,66H,5H,6DH,88H, after which CODE starts from 5000H and becomes DB each data is an address in the data storage area between 0 and 127, or adds 128 to 255 range of a special function register (SFR) address. The access methods for the two are different. In fact, due to PSW‘s reset setting PSW.3=RS0 and PSW.4=RS1 both being 0, the general working register area is the first area, so data from 00 to 07H corresponds to R0 to R7 in the REG bar. The following only represents the low 128 bytes of internal RAM. idata is an address in the range of 0 to 255. idata overlaps with the lower 128 bytes of data, and in some places only DATA indicates 256 bytes of on-chip RAM, xdata is an address in the range of 0-65535. Detailed relationship between pointer types and storage areas: 1. Storage type and storage area relationship data —> addressable on-chip RAM bdata —> bit-addressable on-chip RAM idata —> addressable on-chip RAM, allows access to all internal RAM pdata —> page-addressable external RAM (MOVX @R0) (256 BYTE/page) xdata —> addressable external RAM (64k address range FFFFH) code —> program storage area (64k address range), corresponding to MOVC @DPTR 2. Relationship between pointer types and storage areas When declaring variables, you can specify the storage type of the variable, such as: uchar data x and data uchar x are equivalent, both allocate a byte variable in the internal RAM area. Similarly, for pointer variable declarations, the storage area type keywords are used due to the different storage locations of the pointer variable itself and the storage area pointed to by the pointer. For example: uchar xdata * data pstr indicates allocating a pointer variable in the internal RAM area (the role of the * keyword after data), and this pointer itself points to the xdata area (the role of the xdata keyword before *), which may be a bit difficult to understand and remember for beginners in C51. No worries, we will soon see what happens during compilation with different keywords before and after *. uchar xdata tmp[10]; // Allocates 10 bytes of memory space in external RAM, addresses from 0x0000 to 0x0009 First case: uchar data * data pstr; pstr=”tmp”; First, I must remind everyone that this code has a bug; it cannot correctly access the tmp space in this way. Why? Let’s look at the assembly code after compilation: 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 was used (before the *), it was compiled as a pointer variable pointing to internal RAM according to the KeilC compilation environment. This is also a bug caused by friends who do not understand the definition of various storage type keywords in C51. Especially when the default storage area class in the project is large, and tmp[10] is declared as uchar tmp[10], such bugs are very subtle and not easily discovered. Second case: uchar xdata * data pstr; pstr = tmp; This case is fine; this usage method allocates a pointer variable in the internal RAM (the role of the * keyword after data), and this pointer itself points to the xdata area (the role of the xdata keyword before *). The compiled assembly code is as follows: MOV 0x08,#tmp(0x00); 0x08 and 0x09 are the allocated address space of the pointer variable pstr in the internal RAM area. MOV 0x09,#tmp(0x00). This method should be the most efficient way to access external RAM among all the various situations introduced here, so please remember it. Third case: uchar xdata * xdata pstr; pstr=”tmp”; This case is also correct, but less efficient than the second case. The compiled assembly code is as follows: MOV DPTR, #0x000A; 0x000A and 0x000B are the allocated address space of pointer variable pstr 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 internal RAM resources are relatively tight and efficiency is not highly required. Fourth case: uchar data * xdata pstr; pstr=”tmp”; If readers who have carefully looked at the first case find that this writing is very similar to the first case, yes. Like the first case, this also has a bug, but this time pstr is allocated in the external RAM area. The compiled assembly code is as follows: MOV DPTR, #0x000A; 0x000A is the allocated address space of pointer variable pstr in the external RAM area. MOV A, #tmp(0x00) MOVX @DPTR, A. Fifth case: uchar * data pstr; pstr=”tmp”; Notice that the keyword declaration before * is gone. Yes, what will happen? Let’s see the compiled assembly code. Some may ask, why are we looking at assembly code when we are talking about C51? To use C51 well, we need to improve the efficiency of the compiled C51 code as much as possible, and looking at the compiled assembly will help everyone quickly become proficient in producing efficient C51 code. Let’s look at the code! MOV 0x08, #0X01; 0x08-0x0A are the allocated address space of pointer variable pstr in the internal RAM area. MOV 0x09, #tmp(0x00) MOV 0x0A, #tmp(0x00). Note: This is newly introduced to everyone. You may wonder why the pointer variable pstr in the previous cases used 2 byte space, while here it uses 3 byte space. This is a system internal processing in KeilC, where a pointer variable occupies a maximum of 3 byte space, and for pointers that have not declared the storage space type, the system compiles the code to force load a byte of pointer type distinction value. The specific correspondence can be referred to in the KeilC help under C51 User’s Guide. Sixth case: uchar * pstr; pstr=”tmp”; This is the most direct and simplest pointer variable declaration, but its efficiency is also the lowest. Still, let’s say it together! The compiled assembly code is as follows: MOV DPTR, #0x000A; 0x000A-0x000C are the allocated address space of pointer variable pstr 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 case is very similar to the combination of the fifth and third cases, allocating pstr in the external RAM space while also increasing the pointer type distinction value.
Our official QQ group 1: 281549832
Our official QQ group 2: 386393398
Special thanks to the strong support from netizens.
Our open-source team is constantly expanding, and we hope everyone will come join us!
Here, we still want to thank everyone for their strong support!
Everyone come and follow us!