我用C语言写了一个24CXX的I2C读写模拟程序,在DOS实模式下运行,但是困于一个问题没有成功。
其过程为:先对24CXX某个地址addr写操作,然后再对这个地址读操作,但是读出来的值总是0。可以确认程序的确是从24CXX里读出了字符,但是读写结果不符。现在我把读写的时序贴出来,请教各位:
写操作:
start;
get ack;
tencent DEVICE address;
get ack;
tencent data address;
get ack;
write data;
get ack;
stop;
读操作:
start;
get ack;
tencent DEVICE address;
get ack;
tencent data address;
get ack;
stop;
start;
tencent DEVICE address;
get ack;
read data;
set no_ack;
stop;
请教各位:1。上述时序是否有问题?
2。24CXX芯片是否需要初始化?
3。有过类似编程经验的诸位,能否指点下这其中需要注意的问题?
谢谢。
#include "AT24C02.h"
extern GPIO volatile xdata *gGpio;
// Set Pin
#define I2C_PORT gGpio->PortC
#define SET_PIN(mask) (I2C_PORT.rGPIO_OUT |= (mask))
#define CLR_PIN(mask) (I2C_PORT.rGPIO_OUT &= (~(mask)))
#define DIR_OUT(mask) (I2C_PORT.rGPIO_OE |= (mask) )
// I2C Begin =================
// 功能: 设置SCL Pin的状态,da只能是0或1
void I2C_CLK( unsigned char da )
{
if ( 0 == da )
{
CLR_PIN( SCL );
}
else // da = 1
{
SET_PIN( SCL );
}
}
// 功能: 设置SDA Pin的状态,da只能是0或1
void I2C_DAT( unsigned char da )
{
if ( 0 == da )
{
CLR_PIN( SDA );
}
else // da = 1
{
SET_PIN( SDA );
}
}
void I2C_Delay( void )
{
unsigned int i=0;
for(i=0;i<140;i++) _nop_();
}
void I2C_Start( void )
{
DIR_OUT( SCL | SDA ); // 打开SDA,SCL脚
I2C_DAT( 1 );
I2C_CLK( 1 );
I2C_Delay( );
I2C_DAT( 0 );
I2C_Delay( );
I2C_CLK( 0 );
I2C_Delay( );
}
void I2C_Stop( void )
{
I2C_DAT( 0 );
I2C_CLK( 1 );
I2C_Delay( );
I2C_DAT( 1 );
I2C_Delay( );
I2C_CLK( 0 );
I2C_Delay( );
}
// 得到正确的应答返回0,超时返回1
unsigned char I2C_WaitAck( void )
{
unsigned int errtime=1234;//因故障接收方无ACK,超时值为2550
I2C_CLK( 0 );
I2C_DAT( 1 );
I2C_Delay( );
I2C_CLK( 1 );
I2C_Delay( );
while( (I2C_PORT.rGPIO_IN & SDA) == SDA )
{
if (--errtime==0)
{
I2C_Stop();
LedOn();
return 1;
}
}
I2C_CLK( 0 );
return 0;
}
void I2C_SendACK( void )
{
I2C_DAT( 0 );
I2C_Delay( );
I2C_CLK( 1 );
I2C_Delay( );
I2C_CLK( 0 );
I2C_Delay( );
}
void I2C_SendNoACK( void )
{
I2C_CLK( 0 );
I2C_Delay( );
I2C_DAT( 1 );
I2C_Delay( );
I2C_CLK( 1 );
I2C_Delay( );
I2C_CLK( 0 );
}
unsigned char I2C_Send_Byte( unsigned char ch )
{
unsigned char i;
I2C_CLK( 0 );
for (i=0;i<8; i++)
{
I2C_DAT( (bit)(ch &(0x80>>i)) );
I2C_Delay( );
I2C_CLK( 1 );
I2C_Delay( );
I2C_CLK( 0 );
}
return I2C_WaitAck();
}
unsigned char I2C_Read_Byte( void )
{
unsigned char bdat = 0,i=8;
I2C_CLK( 0 );
I2C_Delay( );
I2C_DAT( 1 );
while(i--)
{
bdat <<= 1;
I2C_CLK( 1 );
I2C_Delay( );
if ( (I2C_PORT.rGPIO_IN & SDA) == SDA )
{
bdat |= 0x01;
}
I2C_CLK( 0 );
I2C_Delay( );
}
return bdat;
}
// end of I2C =================
// AT24C02 Begin ====================
unsigned char E2PROM_Send_Byte( unsigned char ad, unsigned char da )
{
unsigned char SendErr=0;
I2C_Start();
SendErr = I2C_Send_Byte( 0xA0 ); // Chip Address
SendErr += I2C_Send_Byte( ad ); // Address
SendErr += I2C_Send_Byte( da ); // Data
I2C_Stop();
WaitMs( 10 );
return SendErr;
}
unsigned char E2PROM_Read_Byte( unsigned char ad )
{
unsigned char SendErr=0; // 错误标记,暂时不处理
unsigned char temp=0;
I2C_Start();
SendErr = I2C_Send_Byte( 0xA0 ); // Chip Address To Send Address
SendErr += I2C_Send_Byte( ad ) ; // Send Address
I2C_Start();
SendErr += I2C_Send_Byte( 0xA1 ); // Chip Address To Read Data
temp = I2C_Read_Byte( ); // Read Data
I2C_SendNoACK();
I2C_Stop();
WaitMs( 10 );
if ( SendErr ) return 0; // 错误返回0,有可能数据也是0,所以不处理
else return temp; // OK
}
unsigned char E2PROM_Send_Word( unsigned char ad, unsigned int da )
{
unsigned char SendErr=0;
I2C_Start();
SendErr = I2C_Send_Byte( 0xA0 ); // Chip Address
SendErr += I2C_Send_Byte( ad * 2 ); // Address
SendErr += I2C_Send_Byte( da>>8 ); // Data High
SendErr += I2C_Send_Byte( da&0x00FF ); // Data Low
I2C_Stop();
WaitMs( 10 );
return SendErr;
}
unsigned int E2PROM_Read_Word( unsigned char ad )
{
unsigned char SendErr=0;
unsigned int temp=0;
I2C_Start();
I2C_Send_Byte( 0xA0 ); // Chip Address To Send Address
I2C_Send_Byte( ad * 2 ) ; // Send Address
I2C_Start();
I2C_Send_Byte( 0xA1 ) ; // Chip Address To Read Data
temp = I2C_Read_Byte(); // Read Data High
I2C_SendACK();
temp = (temp<<8) + I2C_Read_Byte(); // Read Data Low
I2C_SendNoACK();
I2C_Stop();
WaitMs( 10 );
if ( SendErr != 0 ) return 0 ; // Error
else return temp; // OK
}
// AT24C02 End ======================
希望对你有帮助
to: zhujiujun(<<<<<<<<动感光波>>>>>>>>) ( ) 信誉:100
我用了你提供的程序,经修改测试,还是读写结果不一致。
我用的atmel 24c512, address 为2字节。
另外:set_SDA_HIGH(),set_SDA_LOW(),set_SCL_HIGH(),set_SCL_LOW,get_SDAT()用嵌入汇编写的。具体实现如下:
static void Set_SCLK_LOW(void)
{
asm{
mov dx, PORT_LPT1+2
in ax, dx
or ax, SCL_PIN /*½«SCLÖÃ1 */
out dx, ax
}
}
static void Set_SCLK_HIGH(void)
{
asm{
mov dx,PORT_LPT1+2
in ax,dx
mov bx,SCL_PIN
not bx
and ax,bx /*½«SCLÖÃ0 */
out dx,ax
}
}
static void Set_SDAT_LOW(void)
{
asm{
mov dx,PORT_LPT1
in ax,dx
or ax,SDA_PIN_OUT/*½«SDAÖÃ1 */
out dx,ax
}
}
static void Set_SDAT_HIGH(void)
{
asm{
mov dx,PORT_LPT1
in ax,dx
mov bx,SDA_PIN_OUT
not bx
and ax,bx /*½«SDAÖÃ0 */
out dx,ax
}
}
static unsigned short Get_SDAT(void)
{
asm{
mov dx,PORT_LPT1+1
in ax,dx
not ax /* ½«ax µÄֵȡ·´£¬*/
and ax,SDA_PIN_IN/**/
mov value_SDA_from_AX,ax
}
return value_SDA_from_AX;
}
谢谢。。
读操作:
start;
get ack;
tencent DEVICE address;
get ack;
tencent data address;
get ack;
stop; // 这个地方不应该stop /start
start; //
tencent DEVICE address;
get ack;
read data;
set no_ack;
stop;
以下是在51下模拟IIC总线,连续读EEPROM的时序
I2C_start();
SendByte(Slave); //发送器件地址
if(ack==0) return(0);
SendByte(Subaddr); //发送器件子地址
if(ack==0) return(0);
I2C_start();//不要停后在开始
SendByte(Slave+1); //发送器件地址
if(ack==0) return(0);
for(s=0; s
{
*Source=RecByte(); //接收数据
I2C_Ack(); //发送应答位
Source++;
}
I2C_NAck(); //发送非应答
I2C_stop(); //结束总线
return(1);