IF XDATALEN <> 0
MOV DPTR,#XDATASTART
MOV R7,#LOW (XDATALEN)
IF (LOW (XDATALEN)) <> 0
MOV R6,#(HIGH (XDATALEN)) +1
ELSE
MOV R6,#HIGH (XDATALEN)
ENDIF
CLR A
XDATALOOP: MOVX @DPTR,A
INC DPTR
DJNZ R7,XDATALOOP
DJNZ R6,XDATALOOP
ENDIF
IF PPAGEENABLE <> 0
MOV PPAGE_SFR,#PPAGE
ENDIF
IF PDATALEN <> 0
MOV R0,#LOW (PDATASTART)
MOV R7,#LOW (PDATALEN)
CLR A
PDATALOOP: MOVX @R0,A
INC R0
DJNZ R7,PDATALOOP
ENDIF
IF IBPSTACK <> 0
EXTRN DATA (?C_IBP)
MOV ?C_IBP,#LOW IBPSTACKTOP
ENDIF
IF XBPSTACK <> 0
EXTRN DATA (?C_XBP)
MOV ?C_XBP,#HIGH XBPSTACKTOP
MOV ?C_XBP+1,#LOW XBPSTACKTOP
ENDIF
IF PBPSTACK <> 0
EXTRN DATA (?C_PBP)
MOV ?C_PBP,#LOW PBPSTACKTOP
ENDIF
MOV SP,#?STACK-1
LJMP ?C_START
; Read a trim whose index is in A. Return the trim in A.
CSEG AT 100H
FUSE_TABLE:
DB 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
; Trim test. Prefix "_?" tells Keil C it's reentrant.
_?TRIM_TEST:
PUSH IEN0
PUSH PSW ; Save registers, so it's reentrant.
MOV PSW,00H ; Select registers before saving them
PUSH DPL
PUSH DPH
PUSH ACC
MOV A,R7 ; Save R7 from the current register set.
PUSH ACC
MOV A,R6 ; Save R6 from the current register set.
PUSH ACC
CLR IEN0.7
; Wait for all fuses to be read once before checking fuses
; Complete fuse read takes 45 xtal clock cycles (1 fuse per xtal clock)
MOV R7,#21 ; Wait 21x4 = 48 cycles
loop_inner: DJNZ R7,loop_inner ; 4 cycles (in brownout, 1 cycle/clk)
mov DPH, #HIGH(FUSE_TABLE)
fuse_test_frst: ; check if values previously stored
mov DPL,#LOW(FUSE_TABLE)
clr a
movc a,@a+dptr ; read fuse table
xrl a,#55H
jnz fuse_save
MOV DPTR,#2003H ; Check if in brownout mode
MOVX A,@DPTR
JB ACC.6,PASS ; Mission mode, so don't check.
fuse_test:
mov r7,#8 ; byte counter
fuse_test_lp1:
mov DPTR,#FUSE_TABLE ; load pointer to fuse table
mov a,r7
movc a,@a+dptr ; read fuse table
mov r6,a
mov a,r7
MOV DPTR,#20FDH ; TRIMSEL address
MOVX @DPTR,A ; load reg to read trim
MOV DPL,#0FFH ; TRIM value address
MOVX A,@DPTR ; Get trim value
cjne a,06H,FAIL ; test if flash read and trim ==
djnz r7,fuse_test_lp1
JMP PASS
fuse_save:
MOV DPTR,#2003H ; Check if in brownout mode
MOVX A,@DPTR
; If brownout mode, don't save them and enter sleep.
JNB ACC.6,FAIL
; mov 84H,#LOW(FUSE_TABLE)
mov r7,#8 ; byte counter
fuse_save_lp1:
mov a,r7
MOV DPTR,#20FDH ; TRIMSEL address
MOVX @DPTR,A ; load reg to read trim
MOV DPL,#0FFH ; TRIM value address
MOVX A,@DPTR ; Get trim value
mov r6,a
mov a,r7
mov dptr,#FUSE_TABLE
add a,DPL
mov DPL,a
mov a,r6
orl 0B2H,#01H ; set to flash write
movx @dptr,a ; write fuse table byte
djnz r7,fuse_save_lp1
mov a,#55H ; control byte to mark
mov dptr,#FUSE_TABLE
orl 0B2H,#01H ; set to flash write
movx @dptr,a ; write fuse table byte
jmp PASS
FAIL:
MOV DPTR,#20A9H ; WAKE address
MOV A,#0C1H ; SLEEP forces wake and fuse re-read
MOVX @DPTR,A
PASS: CLR A ; Select 0
MOV DPTR,#20FDH ; TRIMSEL address
MOVX @DPTR,A ; clear trim select register.
POP ACC
MOV R6,A ; Restore R7 in this register set
POP ACC
MOV R7,A ; Restore R7 in this register set
POP ACC
POP DPH
POP DPL
POP PSW ; Restore registers, so it's reentrant.
POP IEN0
RET
END
RTC例程
复位后,软件不应该马上调节时钟修正休眠模式下时差,而是首先计算需要消除的时间偏差,然会设置时钟进行补偿。
评论
查看更多