⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 c518.txt

📁 dsp&c51的编程,从小百合上down的
💻 TXT
📖 第 1 页 / 共 2 页
字号:
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 + -