yanxiao1227 发表于 2010-4-17 11:12:27

51读写24C02 (问题)

我使用了周立功库的一部分,读写24C02,如果只往里写数据,通过单步看,没有问题。
如果只从里面读数据,单步看,也没问题。

但是如果我写了数据,然后在接着读出来,就有问题了,主机发送器件地址,直接接不到回应。。。。
这是怎么回事??

注:我用的是protues+KEIL连调。
程序如下:
#include "reg51.h"
#include "intrins.h"
#include "I2C.h"

sbit SDA=P2^4;                    //*模拟I2C数据传送位
sbit SCL=P2^3;                    //*模拟I2C时钟控制位


#define_Nop()_nop_(),_nop_(),_nop_(),_nop_()      /*定义空指令*/


/*******************************************************************
                     起动总线函数               
函数原型: voidStart_I2c();
功能:   启动I2C总线,即发送I2C起始条件.
********************************************************************/
void Start_I2c()
{
SDA=1;           /*发送起始条件的数据信号*/
_Nop();
SCL=1;
_Nop();            /*起始条件建立时间大于4.7us,延时*/
_Nop();
_Nop();
_Nop();
_Nop();   
SDA=0;           /*发送起始信号*/
_Nop();            /* 起始条件锁定时间大于4μs*/
_Nop();
_Nop();
_Nop();
_Nop();      
SCL=0;           /*钳住I2C总线,准备发送或接收数据 */
_Nop();
_Nop();
}

/*******************************************************************
                     结束总线函数               
函数原型: voidStop_I2c();
功能:   结束I2C总线,即发送I2C结束条件.
********************************************************************/
void Stop_I2c()
{
SDA=0;        /*发送结束条件的数据信号*/
_Nop();           /*发送结束条件的时钟信号*/
SCL=1;        /*结束条件建立时间大于4μs*/
_Nop();
_Nop();
_Nop();
_Nop();
_Nop();
SDA=1;        /*发送I2C总线结束信号*/
_Nop();
_Nop();
_Nop();
_Nop();
}

/*******************************************************************
               字节数据发送函数               
函数原型: bitSendByte(uchar c);
功能:   将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对
          此状态位进行操作.(不应答或非应答都使ack=0)   
             发送数据正常,ack=1; ack=0表示被控器无应答或损坏。
********************************************************************/
bitSendByte(unsigned char c)
{
unsigned charBitCnt;
bit ack;

for(BitCnt=0;BitCnt<8;BitCnt++)/*要传送的数据长度为8位*/
    {
   if((c<<BitCnt)&0x80)SDA=1;   /*判断发送位*/
       elseSDA=0;               
   _Nop();
   SCL=1;               /*置时钟线为高,通知被控器开始接收数据位*/
      _Nop();
      _Nop();             /*保证时钟高电平周期大于4μs*/
      _Nop();
      _Nop();
      _Nop();         
   SCL=0;
    }
   
    _Nop();
    _Nop();
    SDA=1;                /*8位发送完后释放数据线,准备接收应答位*/
    _Nop();
    _Nop();   
    SCL=1;
    _Nop();
    _Nop();
    _Nop();
    if(SDA==1)ack=0;   
       else ack=1;      /*判断是否接收到应答信号*/
    SCL=0;
    _Nop();
    _Nop();
        return ack;
}

/*******************************************************************
               字节数据接收函数               
函数原型: ucharRcvByte();
功能:          用来接收从器件传来的数据,并判断总线错误(不发应答信号),
          发完后请用应答函数应答从机。
********************************************************************/       
unsigned charRcvByte()
{
unsigned char retc;
unsigned char BitCnt;

retc=0;
SDA=1;                             /*置数据线为输入方式*/
for(BitCnt=0;BitCnt<8;BitCnt++)
      {
      _Nop();         
      SCL=0;                  /*置时钟线为低,准备接收数据位*/
      _Nop();
      _Nop();               /*时钟低电平周期大于4.7μs*/
      _Nop();
      _Nop();
      _Nop();
      SCL=1;                  /*置时钟线为高使数据线上数据有效*/
      _Nop();
      _Nop();
      retc=retc<<1;
      if(SDA==1)retc=retc+1;/*读数据位,接收的数据位放入retc中 */
      _Nop();
      _Nop();
      }
SCL=0;   
_Nop();
_Nop();
return(retc);
}




/********************************************************************
                     应答子函数
函数原型:void Ack_I2c(bit a);
功能:      主控器进行应答信号(可以是应答或非应答信号,由位参数a决定)
********************************************************************/
void Ack_I2c(bit a)
{

if(a==0)SDA=0;                /*在此发出应答或非应答信号 */
      else SDA=1;
_Nop();
_Nop();
_Nop();      
SCL=1;
_Nop();
_Nop();                  /*时钟低电平周期大于4μs*/
_Nop();
_Nop();
_Nop();
SCL=0;                     /*清时钟线,钳住I2C总线以便继续接收*/
_Nop();
_Nop();   
}

char AT24C02_WriteByte(char addr,char ch)
{
        Start_I2c();
        if(SendByte(addr)) //发送器件地址
                SendByte(0x01);
       else
               return 0;
        SendByte(ch);
        Stop_I2c();
        return 1;
}
char AT24C02_ReadByte(char addr)
{
    char dat;   

        Start_I2c();
        if(SendByte(addr)) //发送器件地址
                SendByte(0x01);
       else
               return 0;
        Start_I2c();       
        SendByte(addr+1);
        dat=RcvByte();
        Ack_I2c(1);
        Stop_I2c();
        return 1;       
}

主函数:(部分)
        AT24C02_WriteByte(0xa0, 0x55);
        dat=AT24C02_ReadByte(0xa0);

yy625 发表于 2010-5-3 20:10:44

写入数据后应该等待5~10ms再读

详细看数据手册!

yanxiao1227 发表于 2010-5-4 21:55:48

哦 。谢谢。我先试下

k10k10k10 发表于 2010-5-7 16:08:25

直接在AT24C02_WriteByte()里面加延时,或者换成铁电的,嘿嘿
页: [1]
查看完整版本: 51读写24C02 (问题)