📄 c518.txt
字号:
001A 7002 JNZ ?C0004
001C 0500 R INC ptr
001E ?C0004:
001E 14 DEC A
001F FF MOV R7,A
0020 8F82 MOV DPL,R7
0022 8E83 MOV DPH,R6
0024 E0 MOVX A,@DPTR
0025 FF MOV R7,A
0026 8F00 R MOV x,R7
}
0028 80EA SJMP ?C0001
002A ?C0002:
}
002A ?C0003:
002A 22 RET
A variation of this is to declare a pointer to zero and use a variable as an
offset thus:
char xdata *ptr ;
main() {
unsigned int i ;
unsigned char x ;
ptr = (char*) 0x0000 ;
for(i = 0 ;
i < 0x40 ;
i++) {
x = ptr[i] ;
}
}
This results in rather more code, as an addition to the pointer must be perf
ormed within each loop.
7.4 The volatile Storage Class
A common situation with external devices is that values present in their reg
isters change without the cpu taking any action. A good example is a real ti
me clock chip - the time changes continuously without the cpu writing anythi
ng.
Consider the following:
unsigned int xdata *milliseconds = 0x8000 ; // Pointer to
// RTC chip
time = *milliseconds ; -> (1) // Get RTC register value
x = array[time] ;
time = *milliseconds ; -> (2) // Second register access
// optimised out!
y = array[time] ;
Here the value retrieved from the array is related to the value of *millisec
onds, a register in an external RTC.
If this is compiled it will not work. Why? Well the compiler's optimiser sho
ots itself in the foot by assuming that, because no WRITE occurred between (
1) and (2), *millisec cannot have changed. Hence all the code generated to m
ake the second access to the register is optimised out and so y == x!
The solution is declare *milliseconds as "volatile" thus:
unsigned int volatile xdata *milliseconds = 0x8000 ;
Now the optimiser will not try to remove subsequent accesses to the register
.
7.5 Placing Variables At Specific Locations -
The Linker Method
A final method of establishing external variables at fixed addresses, especi
ally arrays, is by using the linker rather than the compiler. For example, t
o produce a 10 character array in external memory, starting at 8000H, the fo
llowing steps are necessary:
/*** Module 1 ***/
/* This module contains only data declarations! */
xdata unsigned char array[30] ;
/* End Module 1 */
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/*** Module 2 ***/
/* This module contains the executable statements */
extern xdata unsigned char array[10] ;
main()
{
unsigned char i ;
i = array[i] ;
}
Now by linking with the invocation:
L51 module1.obj, module2.obj XDATA (?XD?module1 (8000H))
the linker will make the XDATA segment in Module 1 (indicated by ?XD?module1
) start at 8000H, regardless of other xdata declarations elsewhere. Thus the
array starts at 8000H and is 10 bytes (+ null terminator) long.
This approach lacks the flexibility of the above methods but has the advanta
ge of making the linker reserve space in the XDATA space.
Similar control can be exercised over the address of segments in other memor
y spaces. C51 uses the following convention for segment names:
CODE ?PR?functionname?module_name (executable code)
CODE ?CO?functionname?module_name (lookup tables etc.)
BIT ?BI?functionname?module_name
DATA ?DT?functionname?module_name
XDATA ?XD?functionname?module_name
PDATA ?PD?functionname?module_name
Thus the parameter receiving area of a LARGE model function 'test()' in modu
le MOD1.C would be:
?XD?TEST?MOD1,
The code is:
?PR?TEST?MOD1
And so on.
A knowledge of this is useful for assembler interfacing to C51 programs. See
section 14.
7.6 Excluding External Data Ranges From Specific
Areas
This very much follows on from the previous section. Occasionally a memory-m
apped device, such as real time clock chip, is used as both a source of time
values and RAM. Typically the first 8 bytes in the RTC's address range are
the time counts, seconds, minutes etc. whilst the remaining 248 bytes are RA
M.
Left to its own devices, the L51 linker will automatically place any xdata v
ariables starting at zero. If the RTC has been mapped at this address a prob
lem occurs, as the RTC time registers are overwritten. In addition, it would
be convenient to allow the registers to be individually named.
One approach is to define a special module containing just a structure which
describes the RTC registers. In the main program the RTC registers are acce
ssed as elements in the structure. The trick is that, when linking, the XDAT
A segment belonging to the special module is forced to a specific address, h
ere zero. This results in the RTC structure being at zero, with any other XD
ATA variables following on. The basic method could also be used to stop L51
locating any variables in a specific area.
Example Of Excluding Specific Areas From L51
/* Structure located at base of RTC Chip */
MAIN.C Module
extern xdata struct { unsigned char seconds ;
unsigned char minutes ;
unsigned char hours ;
unsigned char days ; } RTC_chip ;
/* Other XDATA Objects */
xdata unsigned char time_secs, time_mins ;
void main(void) {
time_secs = RTC_chip.seconds ;
time_mins = RTC_chip.minutes ;
}
RTCBYTES.C Module
xdata struct { unsigned char seconds ;
unsigned char minutes ;
unsigned char hours ;
unsigned char days ; } RTC_chip ;
Linker Input File To Locate RTC_chip structure over real RTC Registers is:
l51 main.obj,rtcbytes.obj XDATA(?XD?RTCBYTES(0h))
7.7 -missing ORDER and AT now in C51
Perhaps the most curious omission from C51 was the inability to fix the addr
ess of a data object at an absolute address from the source file. Whilst the
re have always been methods of achieving the same effect, users have long re
quested an extension to allow the address of an object to be included in the
original declaration. In C51 v4.xx, the new _AT_control now exists.
7.8 Using The_at_and_ORDER_Controls
Here, the order of the variables must not change as it must match the physic
al location of the real time clock抯 registers. The #pragma ORDER tells c51
to place the data objects at ascending addresses, with the first item at the
lowest address. The linker must then be used to fix the address of the whol
e block in memory.
Source File MAIN.C
#pragma ORDER
unsigned char xdata RTC_secs ;
unsigned char xdata RTC_mins ;
unsigned char xdata RTC_hours ;
main() { RTC_mins = 1 ; }
Linker Input File MAIN.LIN
main.obj & to main & XDATA(?XD?MAIN(0fa00h))
The alternative_at_control forces C51 to put data objects at an address give
n in the source file:
/** Fix Real Time Clock Registers Over Memory-Mapped Device **/
/** Fix each item individually **/
unsigned char xdata RTC_secs _at_ 0xfa00 ;
unsigned char xdata RTC_mins _at_ 0xfa01 ;
unsigned char xdata RTC_hours _at_ 0xfa02 ;
main() { RTC_mins = 1 ;
}
...which hopefully is self-explanatory!
----------------------------------------------------------------------------
----
--
Ours is essentially a tragic age, so we refuse to take it tragically.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -