bit I2C_Start(void);
void I2C_Stop(void);
void I2C_Ack(void);
void I2C_Nack(void);
bit I2C_Send_Byte( uchar);
uchar I2C_Receive_Byte(void);
void AT24C_R(void *mcu_address,uint AT24C_address,uint count);
void AT24C_W(void *mcu_address,uint AT24C_address,uint count);
void Delay_10_uS(void)
{
char i=10;
while(i--);
}
void Delay_N_mS( uint n_milisecond) /* n mS delay */
{
uchar i;
while(n_milisecond--)
{
i=37;
while(i--);
}
}
bit I2C_Start(void)
{
Delay_10_uS();
I2C_SDA =1;
Delay_10_uS();
I2C_SCK =1;
Delay_10_uS();
if ( I2C_SDA == 0) return 0;
if ( I2C_SCK == 0) return 0;
I2C_SDA = 0;
Delay_10_uS();
I2C_SCK = 0;
Delay_10_uS();
return 1;
}
void I2C_Stop(void)
{
Delay_10_uS();
I2C_SDA = 0;
Delay_10_uS();
I2C_SCK = 1;
Delay_10_uS();
I2C_SDA = 1;
Delay_10_uS();
}
void I2C_Ack(void)
{
Delay_10_uS();
I2C_SDA=0;
Delay_10_uS();
I2C_SCK=1;
Delay_10_uS();
I2C_SCK=0;
Delay_10_uS();
}
void I2C_Nack(void)
{
Delay_10_uS();
I2C_SDA=1;
Delay_10_uS();
I2C_SCK=1;
Delay_10_uS();
I2C_SCK=0;
Delay_10_uS();
}
bit I2C_Send_Byte( uchar d)
{
uchar i = 8;
bit bit_ack;
while( i-- )
{
Delay_10_uS();
if ( d &0x80 ) I2C_SDA =1;
else I2C_SDA =0;
Delay_10_uS();
I2C_SCK = 1;
Delay_10_uS();
I2C_SCK = 0;
d = d << 1;
}
Delay_10_uS();
I2C_SDA = 1;
Delay_10_uS();
I2C_SCK = 1;
Delay_10_uS();
bit_ack = I2C_SDA;
I2C_SCK =0;
Delay_10_uS();
return bit_ack;
}
uchar I2C_Receive_Byte(void)
{
uchar i = 8, d;
Delay_10_uS();
I2C_SDA = 1;
while ( i--)
{
d = d << 1;
Delay_10_uS();
I2C_SCK =1;
if ( I2C_SDA ) d++;
Delay_10_uS();
I2C_SCK =0;
}
return d;
}
void AT24C_W(void *mcu_address,uint AT24C_address,uint count)
{
DOG_WDI=!DOG_WDI;
DOGTIME=0;
while(count--)
{
I2C_Start();
/*I2C_Send_Byte( 0xa0 + AT24C_address /256 *2);*/ /* 24C16 USE */
I2C_Send_Byte( 0xa0 );
I2C_Send_Byte( AT24C_address/256 );
I2C_Send_Byte( AT24C_address %256 );
I2C_Send_Byte( *(uchar*)mcu_address );
I2C_Stop();
Delay_N_mS(10); /* waiting for write cycle to be completed */
((uchar*)mcu_address)++;
AT24C_address++;
}
}
void AT24C_R(void *mcu_address,uint AT24C_address,uint count)
{
DOG_WDI=!DOG_WDI;
DOGTIME=0;
while(count--)
{
I2C_Start();
/*I2C_Send_Byte( 0xa0 + AT24C_address / 256 *2 );*/ /* 24C16 USE */
I2C_Send_Byte( 0xa0 );
I2C_Send_Byte( AT24C_address/256 );
I2C_Send_Byte( AT24C_address % 256 );
I2C_Start();
/*I2C_Send_Byte( 0xa1 + AT24C_address /256 *2 );*/
I2C_Send_Byte( 0xa1 );
*(uchar*)mcu_address = I2C_Receive_Byte();
I2C_Nack();
I2C_Stop();
((uchar*)mcu_address)++;
AT24C_address++;
}
}
// AT24C 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< 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< 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< while (!(TWCR & (1< return FALSE; } if(TWI_STATUS != TW_MT_DATA_ACK){ return FALSE; } TWDR = (BYTE)(i&0x00ff); // LSB of address TWCR = (1< while (!(TWCR & (1< 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< while (!(TWCR & (1< 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< while (!(TWCR & (1< return FALSE; } if (TWI_STATUS != TW_MT_DATA_ACK) return FALSE; TWDR = (BYTE)( uiAddress & 0x00ff ); //((BYTE*)(&uiAddress))[0]; // LSB of address TWCR = (1< while (!(TWCR & (1< 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 byEEWait = 3; // 20~30ms while (!(TWCR & (1< 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< return FALSE; } //if (TWI_STATUS != TW_MR_DATA_ACK) // return FALSE; ((BYTE*)pBuf)[i] = TWDR; TwiStop(); return 1; } 附录: ;============================ ;STCC51读写AT24C汇编程序 ;=========================== 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_AT24C ACALL DELAY ACALL READ_AT24C 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_AT24C: ACALL START ;发送起始条件 MOV A, #0A0H ;AT24C总线地址 ACALL SENTBYTE ;发送AT24C器件总线地址 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_AT24C: ;读AT24C ACALL START ;发送IC总线起始条件 MOV A, #0A0H ACALL SENTBYTE ;AT24C总线地址 JB F0, RCVRETURN ;出错返回 MOV R0, #SDADR ;取存储地址 MOV A, @R0 ACALL SENTBYTE ;发送AT24C器件总线地址 JB F0, SENDRETURN ;出错返回 INC R0 MOV A, @R0 ACALL SENTBYTE ;发送AT24C器件总线地址 JB F0, SENDRETURN ACALL START ;发送IC总线重复起始条件 MOV A, #0A0H ;AT24C总线地址 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下载本文