at24c64读写程序
// AT24C64 support functions using ATMEGA's TWI
// pin-WP is hard-wired to GND
// fuctions work better outside interrupt routines
// by MXH, 2003/07/30
#i nclude "DStruct.h"
#i nclude
// CONSTANTS DEFINITION FOR EEPROM
#define EEADDR 0
#define EEWR 0
#define EERD 1
// TWINT *NOT* set after STOP condition is sent
// check status?
// TWSTO is cleared by hardware
#define TwiStop() TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWSTO)
#define TwiStart() TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWSTA)
#define TWI_STATUS (TWSR & 0xF8)
BYTE byEEWait;
//////////////////////////////////////////////////////////////////////////
// implementation
BOOL EEPStart(BYTE addr, BOOL bWrite)
{
byEEWait = 10; // 90~100ms
poll_ack:
TwiStart();
while (!(TWCR & (1< if ( byEEWait == 0 ){ return FALSE; } } if ((TWI_STATUS != TW_START)&&(TWI_STATUS != TW_REP_START)) goto poll_ack; //byEEWait = 3; // 20~30ms // send SLA+R/W TWDR = addr | bWrite; TWCR = (1< while (!(TWCR & (1< if( byEEWait == 0 ){ TwiStop(); return FALSE; } } if( EEWR == bWrite ){ // MT mode //if(TWI_STATUS != TW_MT_SLA_ACK) switch(TWI_STATUS){ case TW_MT_SLA_ACK: break; case TW_MT_SLA_NACK: goto poll_ack; default: TwiStop(); return FALSE; } }else{ // MR mode if(TWI_STATUS != TW_MR_SLA_ACK) return FALSE; } return TRUE; } ////////////////////////////////////////////////////////////////////// // BYTE EEPWrite( WORD uiAddress, WORD uiLen, void *pBuf ) //using 0 { unsigned int i,j,uiCnt; if( uiLen == 0 ) return 0; uiCnt = 0; // uiEnd = uiAddress + uiLen; i = uiAddress; do{ if(!EEPStart(0xA0|EEADDR,EEWR)){ //PollAck() is built-in return 0; } TWDR = (BYTE)((i>>8)&0x00ff); // MSB of address TWCR = (1< byEEWait = 3; // 20~30ms while (!(TWCR & (1< if( byEEWait == 0 ) return FALSE; } if(TWI_STATUS != TW_MT_DATA_ACK){ return FALSE; } TWDR = (BYTE)(i&0x00ff); // LSB of address TWCR = (1< byEEWait = 3; // 20~30ms while (!(TWCR & (1< if( byEEWait == 0 ) return FALSE; } if(TWI_STATUS != TW_MT_DATA_ACK) return FALSE; // write data for( j=0; j<32; j++ ){ TWDR = ((BYTE*)pBuf)[uiCnt]; TWCR = (1< byEEWait = 3; // 20~30ms while (!(TWCR & (1< if( byEEWait == 0 ) return FALSE; } if(TWI_STATUS != TW_MT_DATA_ACK){ return FALSE; } i++; uiCnt++; if(( 0 == i%32 )||( uiCnt == uiLen )){ TwiStop(); break; } } }while( uiCnt < uiLen ); // while( !PollAck()); return 1; } ////////////////////////////////////////////////////////////////////// // BYTE EEPRead( WORD uiAddress, WORD uiLen, void *pBuf ) { UINT i; if ( uiLen == 0 ) return 0; if(!EEPStart(0xA0|EEADDR,EEWR)){ //PollAck() is built-in return 0; //↑ } // not RD but write device address to the chip TWDR = (BYTE)(( uiAddress >> 8) & 0x00ff ); //((BYTE*)(&uiAddress))[1]; // MSB of address TWCR = (1< byEEWait = 3; // 20~30ms while (!(TWCR & (1< if( byEEWait == 0 ) return FALSE; } if (TWI_STATUS != TW_MT_DATA_ACK) return FALSE; TWDR = (BYTE)( uiAddress & 0x00ff ); //((BYTE*)(&uiAddress))[0]; // LSB of address TWCR = (1< byEEWait = 3; // 20~30ms while (!(TWCR & (1< if( byEEWait == 0 ) return FALSE; } if (TWI_STATUS != TW_MT_DATA_ACK) return FALSE; if(!EEPStart(0xA0+EEADDR,EERD)){ //PollAck()){ return 0; //↑ }// ??? how to read? for ( i=0; i TWCR = _BV(TWINT)|_BV(TWEN)|_BV(TWEA); byEEWait = 3; // 20~30ms while (!(TWCR & (1< if( byEEWait == 0 ) return FALSE; } if (TWI_STATUS != TW_MR_DATA_ACK) return FALSE; ((BYTE*)pBuf)[i] = TWDR; // EEInByte(); } TWCR = _BV(TWINT) | _BV(TWEN); // send NACK to indicate final byte byEEWait = 3; // 20~30ms while (!(TWCR & (1< if( byEEWait == 0 ) return FALSE; } //if (TWI_STATUS != TW_MR_DATA_ACK) // return FALSE; ((BYTE*)pBuf)[i] = TWDR; TwiStop(); return 1; } 附录: ;============================ ;STC89C51读写AT24C64汇编程序 ;=========================== BITCNT EQU 42H SDADR EQU 40H SDA BIT P0.1 SCL BIT P0.0 ORG 0000H JMP MAIN ORG 0100H MAIN: MOV R7, #01010101B ACALL WRITE_AT24C64 ACALL DELAY ACALL READ_AT24C64 MOV P3, A ACALL DELAY … ;ACALL 显示、键盘子程序 … JMP MAIN ;============================= DELAY: MOV R6, #0FFH DELAY0: MOV R5, #0FFH DELAY1: DJNZ R5, DELAY1 DJNZ R6, DELAY0 RET ;============================= WRITE_AT24C64: ACALL START ;发送起始条件 MOV A, #0A0H ;AT24C64总线地址 ACALL SENTBYTE ;发送AT24C64器件总线地址 JB F0, SENDRETURN ;出错返回 MOV R0, #SDADR ;取存储地址 MOV A, @R0 ACALL SENTBYTE JB F0, SENDRETURN INC R0 MOV A, @R0 ACALL SENTBYTE JB F0, SENDRETURN MOV A, R7 ACALL SENTBYTE ;发送一次数据 JB F0, SENDRETURN ;出错返回 ACALL STOP ;发送停止条件 DELAY10: MOV R4, #30H ;延时10mS等待数据写完 DELAY11: MOV R3, #34H DJNZ R3, $ DJNZ R4, DELAY11 SENDRETURN: RET ;============================= READ_AT24C64: ;读AT24C64 ACALL START ;发送IC总线起始条件 MOV A, #0A0H ACALL SENTBYTE ;AT24C64总线地址 JB F0, RCVRETURN ;出错返回 MOV R0, #SDADR ;取存储地址 MOV A, @R0 ACALL SENTBYTE ;发送AT24C64器件总线地址 JB F0, SENDRETURN ;出错返回 INC R0 MOV A, @R0 ACALL SENTBYTE ;发送AT24C64器件总线地址 JB F0, SENDRETURN ACALL START ;发送IC总线重复起始条件 MOV A, #0A0H ;AT24C64总线地址 SETB ACC.0 ;取总线读操作数 ACALL SENTBYTE ;发送被控制总线地址 JB F0, RCVRETURN ;出错返回 ACALL RCVBYTE ;接收数据 RCVRETURN: RET ;=============================== START: SETB SDA ;发送起始条件的数据信号 NOP SETB SCL ;发送起始条件的时钟信号 NOP CLR SDA ;发送起始信号 NOP CLR SCL ;准备发送或接收数据 RET ;=============================== STOP: CLR SDA ;发送停止条件的数据信号 NOP SETB SCL ;发送停止条件的时钟信号 NOP SETB SDA ;发送总线停止信号 NOP RET ;============================== SENTBYTE: ;送数8位 MOV BITCNT,#08H SENTB: RLC A ;要发送的数据左移,发送入位C MOV SDA, C SETB SCL ;置时钟线为高,通知被控制开始接 收数据位 CLR SCL ;准备接收下一个数据位 DJNZ BITCNT,SENTB ;8位没发送完继续发送 SETB SDA ;8位发送完后释放数据线准备收应答位 SETB SCL ;开始接收应答信号 CLR F0 ;预先清发送数据出错标志 JNB SDA, ACKEND ;判断是否接收应答信号正常转ACKEND SETB F0 ;未收到应答置位错误标志 ACKEND: CLR SCL ;发送结束准备下次发送或接收数据 RET ;============================== RCVBYTE: SETB SDA ;置数据线为输入方式 MOV BITCNT,#08H ;传送的数据长度为8位 RCV: CLR SCL ;置时钟线为低,准备接收数据 SETB SCL ;置时钟线为高使数据线上数据有效 MOV C, SDA RLC A ;接收的数据位放入ACC DJNZ BITCNT,RCV ;8位没收完继续接收 CLR SCL ;8位接收完置时钟线和数据线 CLR SDA SETB SDA ;接收非应答信号 SETB SCL ;置时钟线为高使应答位有效 SETB SDA CLR SCL ;清时钟线以便发送停止条件 RET ;============================ ;显示、键盘子程序 ;=========================== END