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); 写入数据后应该等待5~10ms再读
详细看数据手册! 哦 。谢谢。我先试下 直接在AT24C02_WriteByte()里面加延时,或者换成铁电的,嘿嘿
页:
[1]