?? c5112.txt
字號:
發信人: reflection (似水流年), 信區: EEtechnology
標 題: C51 Primer (11) Some C51 Tricks
發信站: 南京大學小百合站 (Wed Nov 24 12:04:12 1999), 轉信
11 Some C51 Programming Tricks
11.1 Accessing R0 etc. directly from C51
A C51 user was using existing assembler routines to perform a specific task.
For historical reasons the 8 bit return value from the assembler was left i
n R0 of register bank 3. Ordinarily C51 would return chars in R7 and therefo
re simply equating a variable to the assembler function call would not work.
The solution was to declare an uncommitted memory specific pointer to the DA
TA area. At run time the absolute address of the register (here 0x18) was as
signed to the pointer. The return value was then picked up via the pointer a
fter exiting the assembler section.
/*** Example Of Accessing Specific Registers In C ***/
char data *dptr ; // Create pointer to DATA location
/* Define Address Of Register */
#define R0_bank3 0x40018L /* Address of R0 in */
/* bank 3, 4 => DATA space */
char x,y ;
/* Execute */
main() {
dptr = (char*) R0_bank3 ; // Point at R0, bank3
x = 10 ;
dptr[0] = x ; // Write x into R0, bank3
y = *dptr ; // Get value of R0, bank3
}
An alternative might have been to declare a variable to hold the return valu
e in a separate module and to use the linker to fix that module's DATA segme
nt address at 0x18. This method is more robust and code efficient but is con
siderably less flexible.
11.2 Making Use Of Unused Interrupt Sources
One problem with the 8051 is the lack of a TRAP or software interrupt instru
ction. While C166 users have the luxury of real hardware support for such th
ings, 8051 programmers have to be more cunning.
A situation arose recently where the highest priority interrupt function in
a system had to run until a certain point, from which lesser interrupts coul
d then come in. Unfortunately, changing the interrupt priority registers par
t way through the interrupt function did not work, the lesser interrupts sim
ply waiting until the RETI. The solution was to hijack the unused A/D conver
ter interrupt, IADC, and attach the second section of the interrupt function
to it. Then by deliberately setting the IADC pending flag just before the c
losing "}", the second section could be made to run immediately afterwards.
As the priority of the ADC interrupt had been set to a low level, it was int
erruptable.
/* Primary Interrupt Attached In CC0 Input Capture */
tdc_int() interrupt 8 {
/* High priority section - may not be interrupted */
/* Enable lower priority section attached to */
/* ADC interrupt */
IADC = 1 ; // Force ADCinterrupt
EADC = 1 ; // Enable ADC interrupt
}
/* Lower priority section attached to ADC interrupt */
tdc_int_low_priority() interrupt 10
IADC = 0 ; // Prevent further calls
EADC = 0 ;
/* Low priority section which must be interruptable and */
/* guaranteed to follow high priority section above */
}
11.3 Code Memory Device Switching
This dodge was used during the development of a HEX file loader for a simple
8051 monitor. After receiving a hexfile into a RAM via the serial port, the
new file was to be executed in RAM starting from 0000H. A complication was
that the memory map had to be switched immediately prior to hitting 0000H.
The solution was to place the map switching section at 0xfffd so that the ne
xt instruction would be fetched from 0x0000, thus simulating a reset. Ideall
y all registers and flags should be cleared before this.
"reg.h"
#include "cemb537.h"
#include <stdio.h>
main()
{
unsigned char tx_char,rx_char,i ;
P4 = map2 ;
#include
v24ini_537() ;
timer0_init_537() ;
hexload_ini() ;
EAL = 1 ;
while(download_completed == 0)
{
while(char_received_fl == 0)
{ receive_byte() ; }
tx_byte = rx_byte ; /* Echo */
hexload() ;
send_byte(tx_byte) ;
char_received_fl = 0 ;
}
real_time_count = 0 ;
while(real_time_count < 200)
{ ; }
i = ((unsigned char (code*)(void)) 0xFFFD) () ;
// Jump to absolute address.
}
//^^^^^^^^^^^^^^^^^^^^^^^ End of Module
;
NAME SWITCH
;
; Cause PC to roll-over at FFFFH to simulate reset
;
P4 DATA 0E8H
;
CSEG AT 0FFFDH
;
MOV P4,#02Fh ;
;
END
//^^^^^^^^^^^^^^^^^^^^^^^ End of Module "MAPCON"
There are other ways of doing this. For instance the code for the MAPCON mod
ule could be located at link time thus: CODE(SWITCH(0FFFDH)), so dispensing
with the "CSEG AT".
11.4 Simulating A Software Reset
In a similar vein to the above, the 8051 does not possess a software reset i
nstruction, unlike the 80C166 etc.. This method uses abstract pointers to cr
eate a call to address zero, thus simulating a software reset.
However it should be remembered that all internal locations must be cleared
before the CPU can be considered properly reset! The return address must be
reset as the stack still contains the return address from the call.
;
;
; void main(void) {
RSEG ?PR?main?T1
USING 0
main:
; SOURCE LINE # 9
;
; ((void (code*) (void)) 0x0000) () ;
; SOURCE LINE # 11
LCALL 00H ; Jump to address ZERO!
;
; }
; SOURCE LINE # 13
RET
; END OF main
11.5 The Compiler Preprocessor - #define
This is really just a text replacement device.
It can be used to improve program readability by giving constants meaningful
names, for example:
#define fuel_constant 100 * 2
so that the statement temp = fuel_constant will assign the value 200 to temp
.
Note that the preprocessor only allows integer calculations.
Other more sophisticated examples are given in the C51 manual, pages 4-2.
----------------------------------------------------------------------------
----
--
Ours is essentially a tragic age, so we refuse to take it tragically.
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -