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

📄 c516.txt

📁 dsp&c51的编程,从小百合上down的
💻 TXT
📖 第 1 页 / 共 2 页
字号:
PUSH DPL 

PUSH PSW 

MOV PSW,#08H 

sys_interp() Entry Code 

Still using registerbank 0 

; unsigned char sys_interp(unsigned char x_value, 

RSEG ?PR?_sys_interp?INTERP 

USING 0 

_sys_interp: 

MOV y_value?10,R5 

MOV map_base?10,R2 

MOV map_base?10+01H,R3; 

--Variable 'x_value?10' assigned to Register 'R1' -- 

MOV R1,AR7      <----- FAILS!!!! 

Absolute register addressing used assuming registerbank 0 is still current a 

nd so program fails! (Solutions in 5.3.6-8). 

5.3.4 Notes on C51's "Stack Frame" 

C51 uses a degree of intelligence when entering interrupt functions. Besides 

 the obvious step of substituting RETI for RET at the end of the function, i 

t automatically stacks only those registers that are actually used in the fu 

nction. 

There are however, some points to be aware of: 

If an interrupt function calls a function, C51 will stack all the Ri registe 

rs, regardless of whether they are used or not. The total time to PUSH and P 

OP these is 16us at 12MHz, which may be viewed as unacceptable for a time cr 

itical interrupt. 

Therefore you should either avoid calling functions or use the USING control 

. This will do a simple registerbank switch at the entry and exit from the r 

outine. As the PUSHING of registers onto the stack uses the same overall num 

ber of DATA locations, there is no difference in overall RAM usage. 

Any variable declared within an interrupt function will not be overlaid onto 

 background data or that originating from other interrupts. 

Never call an interrupt function from the background. There is sometimes a t 

emptation to do this during program initialisation, for example. The linker 

will get very confused and will quite likely make dangerous mistakes like ov 

erwriting background variables! 

Using the USING control will generally consume more RAM than simply PUSHing 

registers onto the stack: in the case where the interrupt function employs l 

ess than 8 registers, 8 - <number of registers actually used> will be wasted 

. Thus there is no virtue in avoiding the USING control! 

Interrupts of equal priority can share the same register bank as there is no 

 chance of them interrupting each other. 

5.3.5 When To Use USING 

Interrupts which must run as fast as possible, regardless of overall RAM usa 

ge. 

Interrupts which call other functions. 

5.3.6 The NOAREGS pragma 

Dealing With C51's Absolute Register Addressing. 

As has been pointed out, the 8051 has no MOV Register, Register instruction 

so the compiler uses MOV R1,AR7 where AR7 is the absolute address of the cur 

rent R7. To do this though, the current registerbank number must be known. I 

f a function is called from an interrupt where a using is in force, when com 

piling a called function the compiler must be told: 

(i) not to use absolute register addressing with #pragma NOAREGS control bef 

ore the function, and #pragma RESTORE or #pragmas AREGS control enter the fu 

nction. 

Or: 

(ii) the current registerbank number with #pragma REGISTERBANK(n). 

For (i), applying NOAREGS to the sys_interp function removes the MOV R7,AR7, 

 replacing it with an awkward move of R7 to R1 using XCH A,Ri! 

timer0_int Entry Code 

; void timer0_int(void) interrupt 1 using 1 { 

RSEG ?PR?timer0_int?TIMER0 

USING 1 

timer0_int: 

PUSH ACC 

PUSH B 

PUSH DPH 

PUSH DPL 

PUSH PSW 

MOV PSW,#08H 

sys_interp() Entry Code With NOAREGS 

; unsigned char sys_interp(unsigned char x_value, 

RSEG ?PR?_sys_interp?INTERP 

USING 0 

_sys_interp: 

MOV y_value?10,R5 

MOV map_base?10,R2 

MOV map_base?10+01H,R3; 

--Variable 'x_value?10' assigned to Register 'R1' -- 

XCH A,R1 ; 

MOV A,R7 ; Slow Reg to Reg move 

5.3.7 The REGISTERBANK Control Alternative To NOAREGS 

#pragma REGISTERBANK(n) tells C51 the absolute address of the current "using 

" registerbank base so that direct register addressing will work. 

EXAMPLE: 

/* Timer 0 Overflow Interrupt Service Routine */ 

timer0_int() interrupt 1 USING 1 { 

unsigned char temp1 ; 

unsigned char temp2 ; 

/* executable C statements */ 

 } 

Called function: 

#pragma SAVE // Rember current registerbank 

#pragma REGISTERBANK(1) // Tel C51 base address of current registerbank. 

void func(char x) {     // Called from interrupt routine 

// with "using1" 

/* Code */ 

 } 

#pragma RESTORE // Put back to original registerbank 

Applying #pragma REGISTERBANK(1) to sys_interp() restores absolute register 

addressing as C51 now knows the base address of the current register bank. 

Note: Always try to use the REGISTERBANK(n) control for any functions called 

 from an interrupt with a USING! 

sys_interp() Entry Code With REGISTERBANK(n) 

; unsigned char sys_interp(unsigned char x_value, 

RSEG ?PR?_sys_interp?INTERP 

USING 1 

_sys_interp: 

MOV y_value?10,R5 

MOV map_base?10,R2 

MOV map_base?10+01H,R3;-- 

Variable 'x_value?10' assigned to Register 'R1' -- 

MOV R1,AR7 

5.3.8 Summary Of USING And REGISTERBANK 

Expressed in psuedo-code! 

if(interrupt routine = USING 1){ 

subsequently called function uses #pragma REGISTERBANK(1) 

} 

Note: subsequently called function must now only be called from functions us 

ing register bank 1. 

5.3.9 Reentrancy In C51 - The Final Solution 

In addition to calling a function from interrupt, it is also sometimes neces 

sary to call the same function from the background as well. This leaves the 

possibility open that the function may be called from two places simultaneou 

sly with disasterous results! 

The attribute required to permit a function to be safely called both from ba 

ckground and interrupt routines simultaneously is "reentrant". This can also 

 help in the previous situation of a function being called from an interrupt 

. The linker's "MULTIPLE CALL TO SEGMENT" warning is the first sign that you 

 may be trying to use a function reentrantly. 

Due to the way that C51 allocates storage for local variables and parameters 

, it is not possible to call a function from both an interrupt and the backg 

round loop. To allow only those functions to be used reentrantly that really 

 need to be, it is possible to specify the reentrant attribute when declarin 

g a function. 

The ?C_IBP value set up in startup.a51 tells C51 where to locate the artific 

ial stacks used for reentrant functions. Each time a reentrant function is c 

alled, its incoming parameters are moved from the registers in which they we 

re passed into an area of RAM, starting at the address indicated by ?C_IBP. 

Likewise, any local variables used by the reentrant function are also alloca 

ted a place on this special stack. 

When startup.a51 is executed before main(), the line: 

IF IBPSTACK <> 0 

EXTRN DATA (?C_IBP) 

MOV ?C_IBP,#LOW IBPSTACKTOP 

ENDIF 

initialises ?C_IBP to the value of IBPSTACKTOP that you set up earlier. As e 

ach local is "pushed" on to the reentrant stack, ?C_IBP is decremented. Thus 

 if an interrupt occurs which calls the function again, the new call will st 

art its reentrant stack from the current ?C_IBP value. Thereafter, any local 

 data or parameter is accessed by the code sequence: 

Get a local variable at offset 2 from the current base of the re-entrant sta 

ck: 

MOV R0,?C_IBP ; Get stack base 

MOV A,@R0 ;     Add offset of local 

ADD A,#002 ; 

MOV A,@R0 ;     Get local via indirect addressing. 

MOV R7,A ;      Store value whilst other local is ; 

accessed. 

On leaving the function, ?C_IBP is restored to entry value by adding the tot 

al number of locals and parameters that were used. This represents a very la 

rge overhead and shows why reentrancy should only be used where absolutely n 

ecessary. 

EXAMPLE: 

The Reentrant Stack When Located In The IDATA Area 

0xff    sys_interp parameter 0 

0xfe    sys_interp parameter 1 

0xfd    sys_interp parameter 2L 

0xfc    sys_interp parameter 2H - call from background: 

  

 ?C_IBP= 0xfc 

0xfb    sys_interp parameter 0 

0xfa    sys_interp parameter 0 

0xf9    sys_interp parameter 1 

0xf8    sys_interp parameter 2L 

0xf7    sys_interp parameter 2H - call from timer0 

interrupt: ?C_IBP = 0xf7 

0xf6    sys_interp parameter 0 

0xf5    sys_interp parameter 0 

0xf4    sys_interp parameter1 

0xf3    sys_interp parameter 2L 

0xf2    sys_interp parameter 2H - call from background 

  

?C_IBP = 0xf2 

0xf1 

0xf0 

0xef 

0xee 

?C_IBP acts as a base pointer to the reentrant stack and is used to access a 

ll locals in a reentrant function. 

Adding the reentrant attribute to sys_interp() still requires the NOAREGS co 

ntrol as the registerbank has been changed by USING 1. As a matter of policy 

, any reentrant function should also have the NOAREGS control so that it bec 

omes totally registerbank-independent. 

sys_interp() Entry Code 

; unsigned char interp_sub(unsigned char x, 

RSEG ?PR?_?interp_sub?INTERP 

USING 0 

_?interp_sub: 

DEC ?C_IBP 

DEC ?C_IBP 

MOV R0,?C_IBP 

XCH A,@R0 

MOV A,R2 

XCH A,@R0 

INC R0 

XCH A,@R0 

MOV A,R3 

XCH A,@R0 

DEC ?C_IBP 

MOV R0,?C_IBP 

XCH A,@R0 

MOV A,R5 

XCH A,@R0 

DEC ?C_IBP 

MOV R0,?C_IBP 

XCH A,@R0 

MOV A,R7 

XCH A,@R0 

DEC ?C_IBP ; 

 SOURCE LINE # 22 

sys_interp() Exit Code 

?C0009: 

MOV A,?C_IBP 

 ADD A,#010H   <-- Restore ?C_IBP to original 

position 

MOV ?C_IBP,A 

RET ; 

END OF _?sys_interp 

END 

5.3.10 Summary Of Controls For Interrupt Functions 

Provided the following combinations of controls are used, you will avoid lin 

ker warnings and potentially dangerous code. 

Interrupt Function Attribute      |    Called Function Attribute: 

----------------------------------|----------------------------------- 

                                  |    "non-reentrant" 

No USING                          |    no special attribute required 

USING n                           |    USING n 

                                  |    or 

                                  |    #pragma REGISTERBANK(n) 

                                  |    or 

                                  |    #pragma NOAREGS 

Interrupt Function Attribute      |    Called Function Attribute 

---------------------------------------------------------------------- 

                                  |    "reentrant" 

         no USING                 |    no register attribute 

         USING n                  |    #pragma NOAREGS 

5.3.11 Reentrancy And Library Functions 

The majority of C51 library functions are reentrant and can be freely used f 

rom interrupts and background. However, some larger library functions such a 

s printf(), scanf() etc. are not reentrant. If you have used a non-reentrant 

 library function reentrantly, you will get a "MULTIPLE CALL TO SEGMENT" war 

ning, as would be expected. 

"Hidden" library functions used to perform integer divides and multiplies et 

c. are all reentrant so you can perform a 16/16 divide in an interrupt witho 

ut fear of upsetting the background. 

To Summarise: 

You can generally use library functions reentrantly but always check the C51 



 manual section 9 to check whether a function is reentrant or not. 

---------------------------------------------------------------------------- 

---- 

  

-- 

Ours is essentially a tragic age, so we refuse to take it tragically. 

  

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -