请教:24CXX的I2C读写时序问题

sdlrf123   2007-4-16 19:10 楼主
我用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。有过类似编程经验的诸位,能否指点下这其中需要注意的问题?  

       谢谢。

回复评论 (6)


#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 ======================



希望对你有帮助
点赞  2007-4-16 20:25
写EEPROM需要延时,
点赞  2007-4-17 08:37
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;
}

谢谢。。
点赞  2007-4-17 10:57
读操作:  
             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;  

点赞  2007-5-23 11:31
看看读写标志,明确后面的数据是要读,还是要写。
点赞  2007-8-20 11:12
以下是在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);
点赞  2007-8-24 22:08
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复