[转帖]AT24Cxx i2c控制程序
<P>NAME Control_AT24Cxx</P><P>; This collection of routines allows an AT89C2051 microcontroller to read
; and write the AT24Cxx family of serial CMOS EEPROMS. This version of the
; code is compatible only with the AT89C2051 due to the location of the
; data buffer and stack in RAM. The code may be modified to work with the
; AT89C1051 by relocating or resizing the buffer and stack to fit into the
; smaller amount of RAM available in the AT89C1051. Note that the minimum
; size of the buffer is determined by the page size of the AT24Cxx.
;
; All five AT24Cxx device operations are supported. Byte Write, Current
; Address Read and Random Read are implemented by the functions WRITE_BYTE,
; READ_CURRENT and READ_RANDOM, respectively. Page Write and Sequential Read
; are special cases of functions WRITE_BLOCK and READ_BLOCK, respectively.
; WRITE_BLOCK and READ_BLOCK process from one byte to the number of bytes
; in a page and transfer data between the AT24Cxx and the RAM buffer.
;
; The code supports multiple AT24Cxx devices per bus, each with a unique
; address determined by the wiring of the address pins (A0, A1, A2). The
; three-bit programmable address is passed to the WRITE_BYTE, READ_CURRENT,
; READ_RANDOM, WRITE_BLOCK and READ_BLOCK functions, where it is combined
; with the AT24Cxx fixed address (FADDR) and used to address a device on the
; bus. Refer to the AT24Cxx family data sheets for additional information on
; device addressing.
;
; Functions BYTE_FILL, VERIFY_BYTE_FILL, PAGE_FILL and VERIFY_PAGE_FILL are
; artifacts from the debug process and serve to illustrate the use of the
; device read and write functions with an AT24C64. To modify the code for a
; different member of the AT24Cxx family, simply redefine the values of SIZE
; (the number of bytes per device) and PSIZE (the number of bytes per page).
; To change the fill value, redefine FILL. To change the programmable portion
; of the device address, redefine PADDR to a value from zero to seven.
;
; The code meets all AT24Cxx family timing requirements when executed by an
; AT89Cx051 microcontroller with a 12 MHz clock. Code modifications may be
; required if a faster clock is substituted.</P>
<P>
FADDREQU 0a0h; fixed address for AT24Cxx EEPROMs
PADDREQU 0; programmable address (0..7)
SIZEEQU 2000h; bytes per AT24C64
PSIZEEQU 32; bytes per page for AT24C64
FILLEQU 55h; example fill value</P>
<P>; Register definitions.</P>
<P>indexEQU r0; buffer pointer
kountEQU r1; byte count register
zdataEQU r1; data register
addr_loEQU r2; 2-byte address register
addr_hiEQU r3;</P>
<P>; Microcontroller connections to AT24Cxx serial bus lines.</P>
<P>SCLBIT p1.2; serial clock
SDABIT p1.3; serial data</P>
<P>
DSEG AT 20H</P>
<P>ORG 40H
buffer:DS PSIZE; storage for read/write data</P>
<P>ORG 60H; stack origin
stack:DS 20H; stack depth</P>
<P>
CSEG</P>
<P>ORG 0000H; power on/reset vector
jmp on_reset</P>
<P>ORG 0003H; external interrupt 0 vector
reti ; undefined</P>
<P>ORG 000BH; timer 0 overflow vector
reti ; undefined</P>
<P>ORG 0013H; external interrupt 1 vector
reti ; undefined</P>
<P>ORG 001BH; timer 1 overflow vector
reti ; undefined</P>
<P>ORG 0023H; serial I/O interrupt vector
reti ; undefined</P>
<P>ORG 0080H; begin code space
USING 0; register bank zero
on_reset:
mov sp, #(stack-1) ; initialize stack pointer</P>
<P>; Initialize AT24Cxx serial bus lines.</P>
<P>setb SDA; high
setb SCL; high</P>
<P>
call byte_fill
jc fault</P>
<P>call verify_byte_fill
jc fault</P>
<P>call page_fill
jc fault</P>
<P>call verify_page_fill
jc fault</P>
<P> fault:
jmp $</P>
<P>
byte_fill:</P>
<P> ; Fill every byte in an AT24Cxx with the same value.
; Writes one address at a time (page mode is not used).
; Returns CY set to indicate write timeout.
; Destroys A, B, DPTR, XDATA, ADDR_HI:ADDR_LO.</P>
<P>mov zdata, #FILL ; set up fill data
mov dptr, #0 ; initialize address pointer
x51:
mov addr_lo, dpl ; set up address
mov addr_hi, dph ;</P>
<P>mov b, #120; retry counter
x52:
mov a, #PADDR ; programmable address
call write_byte ; try to write
jnc x53; jump if write OK</P>
<P>djnz b, x52; try again
setb c; set timeout error flag
jmp x54; exit
x53:
inc dptr ; advance address pointer
;mov a, dpl ; check low byte
;cjne a, #(LOW SIZE), x51 ; jump if not last
mov a, dph ; check high byte
cjne a, #(HIGH SIZE), x51 ; jump if not last
clr c ; clear error flag
x54:
ret</P>
<P>
verify_byte_fill:</P>
<P> ; Verify that all bytes in an AT24Cxx match a fill value.
; Reads and verifies one byte at a time (page mode is not used).
; Performs a Random Read function to initialize the internal
; address counter and checks the contents of the first address.
; Then performs multiple Current Address Read functions to step
; through the remaining addressess.
; Returns CY set to indicate read timeout or compare fail.
; Destroys A, B, DPTR.</P>
<P>mov dptr, #0 ; initialize address pointer/counter
mov addr_lo, dpl ; set up address
mov addr_hi, dph ;</P>
<P>mov b, #120; retry counter
x81:
mov a, #PADDR ; programmable address
call read_random ; try to read
jnc x82; jump if read OK</P>
<P>djnz b, x81; try again
jmp x86; set error flag and exit
x82:
cjne a, #FILL, x86 ; jump if compare error
jmp x85; do remaining addresses
x83:
mov a, #PADDR
call read_current
jc x87; jump if read fails</P>
<P>cjne a, #FILL, x86 ; jump if compare error
x85:
inc dptr ; advance address pointer
mov a, dph ; check high byte
cjne a, #(HIGH SIZE), x83 ; jump if not last
clr c ; clear error flag
jmp x87; exit
x86:
setb c; set error flag
x87:
ret</P>
<P>
page_fill:</P>
<P> ; Fill every byte in an AT24Cxx with the same value.
; Writes one page at a time.
; Returns CY set to indicate write timeout.
; Destroys A, B, DPTR, KOUNT, INDEX, ADDR_HI:ADDR_LO.</P>
<P>; First fill buffer.</P>
<P>mov b, #PSIZE ; bytes per page
mov index, #buffer ; point to buffer
x61:
mov @index, #FILL ; put fill value in buffer
inc index; advance pointer
djnz b, x61; next byte</P>
<P>; Copy buffer to device, one page at a time.</P>
<P>mov dptr, #0 ; initialize address pointer
x62:
mov addr_lo, dpl ; set up address
mov addr_hi, dph ;
mov kount, #PSIZE ; bytes per page</P>
<P>mov b, #120; retry counter
x63:
mov a, #PADDR ; programmable address
call write_block ; try to write
jnc x64; jump if write OK</P>
<P>djnz b, x63; try again
setb c; set timeout error flag
jmp x66; exit
x64:
; Add page size to address pointer.</P>
<P>mov a, dpl; get low byte
add a, #PSIZE ; add page size
mov dpl, a; save low byte
jnc x65; jump if high byte not affected
inc dph; increment high byte
x65:
;cjne a, #(LOW SIZE), x62 ; jump if low byte not last
mov a, dph ; check high byte
cjne a, #(HIGH SIZE), x62 ; jump if not last
clr c ; clear error flag
x66:
ret</P>
<P>
verify_page_fill:</P>
<P> ; Verify that all bytes in an AT24Cxx match a fill value.
; Reads and verifies one page at a time.
; Returns CY set to indicate read timeout or compare fail.
; Destroys A, B, DPTR, KOUNT, INDEX, ADDR_HI:ADDR_LO.</P>
<P>; Copy device page to buffer.</P>
<P>mov dptr, #0 ; initialize address pointer
x71:
mov addr_lo, dpl ; set up address
mov addr_hi, dph ;
mov kount, #PSIZE ; bytes per page</P>
<P>mov b, #120; retry counter
x72:
mov a, #PADDR ; programmable address
call read_block ; try to read
jnc x74; jump if read OK</P>
<P>djnz b, x72; try again
x73:
setb c; set error flag
jmp x77; exit
x74:
; Verify buffer contents.</P>
<P>mov b, #PSIZE ; bytes per page
mov index, #buffer ; point to buffer
x75:
cjne @index, #FILL, x73 ; jump if compare fails
inc index; advance pointer
djnz b, x75; next byte</P>
<P>; Add page size to address pointer.</P>
<P>mov a, dpl; get low byte
add a, #PSIZE ; add page size
mov dpl, a; save low byte
jnc x76; jump if high byte not affected
inc dph; increment high byte
x76:
;cjne a, #(LOW SIZE), x71 ; jump if low byte not last
mov a, dph ; check high byte
cjne a, #(HIGH SIZE), x71 ; jump if not last
clr c ; clear error flag
x77:
ret</P>
<P>
write_block:</P>
<P> ; Write from one byte to one page of data to an AT24Cxx.
; Called with programmable address in A, address of first byte
; in register pair ADDR_HI:ADDR_LO, data in BUFFER, byte count
; in register KOUNT.
; Does not wait for write cycle to complete.
; Returns CY set to indicate that the bus is not available
; or that the addressed device failed to acknowledge.
; Destroys A, KOUNT, INDEX.</P>
<P>call start
jc x38; abort if bus not available</P>
<P>rl a; programmable address to bits 3:1
orl a, #FADDR ; add fixed address
clr acc.0; specify write operation
call shout; send device address
jc x37; abort if no acknowledge</P>
<P>mov a, addr_hi ; send high byte of address
call shout;
jc x37; abort if no acknowledge</P>
<P>mov a, addr_lo ; send low byte of address
call shout;
jc x37; abort if no acknowledge</P>
<P>mov index, #buffer ; point to buffer
x36:
mov a, @index ; get data
call shout; send data
jc x37; abort if no acknowledge</P>
<P>inc index; advance buffer pointer
djnz kount, x36 ; next byte
clr c; clear error flag
x37:
call stop
x38:
ret</P>
<P>
read_block:</P>
<P> ; Read from one byte to one page of data from an AT24Cxx.
; Performs a Random Read which is extended into a Sequential Read
; when more than one byte is read. Called with programmable address
; in A, address of first byte in register pair ADDR_HI:ADDR_LO,
; byte count in register KOUNT.
; Returns data in BUFFER. Returns CY set to indicate that the bus is
; not available or that the addressed device failed to acknowledge.
; Destroys A, KOUNT, INDEX.</P>
<P>; Send dummy write command to address first byte.</P>
<P>call start
jc x35; abort if bus not available</P>
<P>rl a; programmable address to bits 3:1
orl a, #FADDR ; add fixed address
mov index, a ; save copy of device address
clr acc.0; specify write operation
call shout; send device address
jc x34; abort if no acknowledge</P>
<P>mov a, addr_hi ; send high byte of address
call shout;
jc x34; abort if no acknowledge</P>
<P>mov a, addr_lo ; send low byte of address
call shout;
jc x34; abort if no acknowledge</P>
<P>; Send read command and receive data.</P>
<P>call start; second start for read
jc x34; abort if bus not available</P>
<P>mov a, index ; get device address
setb acc.0; specify read operation
call shout; send device address
jc x34; abort if no acknowledge</P>
<P>mov index, #buffer ; point to buffer
x31:
call shin; receive data byte
mov @index, a ; save data</P>
<P>cjne kount, #1, x32 ; jump if not last byte
call NAK; do not acknowledge last byte
jmp x33; done
x32:
call ACK; acknowledge byte
inc index; advance buffer pointer
djnz kount, x31 ; next byte
x33:
clr c; clear error flag
x34:
call stop
x35:
ret</P>
<P>
write_byte:</P>
<P> ; AT24Cxx Byte Write function.
; Called with programmable address in A, byte address in
; register pair ADDR_HI:ADDR_LO, data in register XDATA.
; Does not wait for write cycle to complete.
; Returns CY set to indicate that the bus is not available
; or that the addressed device failed to acknowledge.
; Destroys A.</P>
<P>call start
jc x49; abort if bus not available</P>
<P>rl a; programmable address to bits 3:1
orl a, #FADDR ; add fixed address
clr acc.0; specify write operation
call shout; send device address
jc x48; abort if no acknowledge</P>
<P>mov a, addr_hi ; send high byte of address
call shout;
jc x48; abort if no acknowledge</P>
<P>mov a, addr_lo ; send low byte of address
call shout;
jc x48; abort if no acknowledge</P>
<P>mov a, zdata ; get data
call shout; send data
jc x48; abort if no acknowledge</P>
<P>clr c; clear error flag
x48:
call stop
x49:
ret</P>
<P>
read_current:</P>
<P> ; AT24Cxx Current Address Read function.
; Called with programmable address in A. Returns data in A.
; Returns CY set to indicate that the bus is not available
; or that the addressed device failed to acknowledge.</P>
<P>call start
jc x45; abort if bus not available</P>
<P>rl a; programmable address to bits 3:1
orl a, #FADDR ; add fixed address
setb acc.0; specify read operation
call shout; send device address
jc x44; abort if no acknowledge</P>
<P>call shin; receive data byte
call NAK; do not acknowledge byte
clr c; clear error flag
x44:
call stop
x45:
ret</P>
<P>
read_random:</P>
<P> ; AT24Cxx Random Read function.
; Called with programmable address in A, byte address in
; register pair ADDR_HI:ADDR_LO. Returns data in A.
; Returns CY set to indicate that the bus is not available
; or that the addressed device failed to acknowledge.</P>
<P>push b
mov b, a; save copy of programmable address</P>
<P>; Send dummy write command to set internal address.</P>
<P>call start
jc x47; abort if bus not available</P>
<P>rl a; programmable address to bits 3:1
orl a, #FADDR ; add fixed address
clr acc.0; specify write operation
call shout; send device address
jc x46; abort if no acknowledge</P>
<P>mov a, addr_hi ; send high byte of address
call shout;
jc x46; abort if no acknowledge</P>
<P>mov a, addr_lo ; send low byte of address
call shout;
jc x46; abort if no acknowledge</P>
<P>; Call Current Address Read function.</P>
<P>mov a, b; get programmable address
call read_current
jmp x47; exit
x46:
call stop
x47:
pop b
ret</P>
<P>
</P> start:<P> ; Send START, defined as high-to-low SDA with SCL high.
; Return with SCL, SDA low.
; Returns CY set if bus is not available.</P><P>setb SDA
setb SCL</P><P>; Verify bus available.</P><P>jnb SDA, x40 ; jump if not high
jnb SCL, x40 ; jump if not high</P><P>nop ; enforce setup delay and cycle delay
clr SDA
nop ; enforce hold delay
nop ;
nop ;
nop ;
nop ;
clr SCL</P><P>clr c; clear error flag
jmp x41
x40:
setb c; set error flag
x41:
ret</P><P>
stop:</P><P> ; Send STOP, defined as low-to-high SDA with SCL high.
; SCL expected low on entry. Return with SCL, SDA high.</P><P>clr SDA
nop ; enforce SCL low and data setup
nop
setb SCL
nop ; enforce setup delay
nop ;
nop ;
nop ;
nop ;
setb SDA
ret</P><P>
shout:</P><P> ; Shift out a byte to the AT24Cxx, most significant bit first.
; SCL, SDA expected low on entry. Return with SCL low.
; Called with data to send in A.
; Returns CY set to indicate failure by slave to acknowledge.
; Destroys A.</P><P>push b
mov b, #8; bit counter
x42:
rlc a; move bit into CY
mov SDA, c; output bit
nop ; enforce SCL low and data setup
setb SCL; raise clock
nop ; enforce SCL high
nop ;
nop ;
nop ;
clr SCL; drop clock
djnz b, x42; next bit</P><P>setb SDA; release SDA for ACK
nop ; enforce SCL low and tAA
nop ;
setb SCL; raise ACK clock
nop ; enforce SCL high
nop ;
nop ;
nop ;
mov c, SDA; get ACK bit
clr SCL; drop ACK clock</P><P>pop b
ret</P><P>
shin:</P><P> ; Shift in a byte from the AT24Cxx, most significant bit first.
; SCL expected low on entry. Return with SCL low.
; Returns received data byte in A.</P><P>setb SDA; make SDA an input</P><P>push b
mov b, #8; bit count
x43:
nop ; enforce SCL low and data setup
nop ;
nop ;
setb SCL; raise clock
nop ; enforce SCL high
nop ;
mov c, SDA; input bit
rlc a; move bit into byte
clr SCL; drop clock
djnz b, x43; next bit</P><P>pop b
ret</P><P>
ACK:</P><P> ; Clock out an acknowledge bit (low).
; SCL expected low on entry. Return with SCL, SDA low.</P><P>clr SDA; ACK bit
nop ; enforce SCL low and data setup
nop ;
setb SCL; raise clock
nop ; enforce SCL high
nop ;
nop ;
nop ;
clr SCL; drop clock
ret</P><P>
NAK:</P><P> ; Clock out a negative acknowledge bit (high).
; SCL expected low on entry. Return with SCL low, SDA high.</P><P>setb SDA; NAK bit
nop ; enforce SCL low and data setup
nop ;
setb SCL; raise clock
nop ; enforce SCL high
nop ;
nop ;
nop ;
clr SCL; drop clock
ret</P><P>
END
</P>
页:
[1]