#include <reg52.h>

#include <intrins.h>      //包含机器周期延时函数_nop_()

#define OP_READ 0xa1    //器件地址以及读取操作 1010 0001B

#define OP_WRITE 0xa0   //器件地址以及写入操作 1010 0000B

/*说明:器件地址为前7位,最低一位为选择读或写*/

sbit SDA=P3^5;

sbit SCL=P3^4;

/* 延时1ms*/

void delay1ms()

{

unsigned char I,j;

for(i=0;i<10;i++)

for(j=0;j<33;j++)

;

}

/*延时若干毫秒*/

void delayms(unsigned char n)

{

Unsigned char j;

For(i=0;i<n;i++)

Delay1ms();

}

/*开始数据传送的前期准备*/

Void start()

{

SDA=1;      //SDA初始化为高电平

SCL=1;      //SCL初始化为高电平

_nop_();

_nop_();

_nop_();

_nop_();

SDA=0;    //在SCL为高电平时,SDA由1置0被认为是开始信号

_nop_();

_nop_();

_nop_();

_nop_();

SCL=0;   //SCL变为低电平,开始传送数据

}

/*结束数据传送*/

Void stop()

{

SDA=0;   //SDA初始化为低电平,准备发出终止信号

SCL=1;   //SCL变成高电平,此时SDA的一切变化都将被认为是开始或终止信号

_nop_();

_nop_();

_nop_();

_nop_();

SDA=1;    //在SCL为高电平时,SDA由0置1被认为是终止信号

_nop_();

_nop_();

_nop_();

_nop_();

SCL=0;   

SDA=0;    //解除总线的占用

}


/*从子器件读取数据*/

Unsigned char ReadData()

{

Unsigned char i,x;  //规定两个中间变量用于暂时存储数据

For(i=0;i<8;i++)    //循环8次,刚好记录一个字节

{

              SCL=1;    //先不允许SDA变化,便于记录数据

              X <<=1;     //将x各二进制位向左移一位

X |=(unsigned char)SDA;   //将SDA的数据存到X里

/***说明: X有定义之后默认为0x00,SDA为从最高位向最低位变化,所以左移可以将数据按从高到低存储在x里;

SDA为一个二进制位,转换成unsigned char 之后变成字节的最低位,所以按位与运算之后可将SDA当前数据存储在X的当前最低位*******/

SCL=0;   //允许SDA变换到下一位

}

Return (x);  //将最终记录好的X值返回给外函数变量

}



/* 向从机写入数据*/

//调用该函数之前要先调用start(),所以SCL=0;

Bit WriteCurrent(unsigned char y)

{

Unsigned char i;

Bit ack_bit;          //储存应答位

For(i=0;i<8;i++)

{

              SDA=(bit)(y&0x80);

/**先与0x80按位与运算以得到最高位信息(发送时仍先发送最高位),再按照bit 的强制类型转换规则,如果得到1000 0000,则最高位为1,此时SDA为1;如果得到0000 0000,则最高位为0,SDA=0**/

              _nop_();

SCL=1;    //不允许SDA变化,方便从机记录数据

              _nop_();

_nop_();

              SCL=0;  //从机记录完成该位,可变换为下一位

              Y<<=1;   //让次高位位变成最高位以进行下一次数据传输

}

/*开始检测应答位*/

SDA=1;    //初始化SDA,并让其自由变换

_nop_();

_nop_();

SCL=1;   //SCL置1,开始检测是否应答(SDA的值在这之前已经变化完成)

_nop_();

_nop_();

_nop_();

_nop_();

Ack_bit=SDA;  //记录应答位的值

SCL=0;     

return ack_bit;   //返回应答位的值,让外部得知是否应答

}


/* 向指定从机写入地址和数据,add存储指定地址,dat存储待写入的数据*/

Void WriteSet(unsigned char add,unsigned char dat)

{

Start();  //初始化总线

WriteCurrent(OP_WRITE);  //选择从机并告知要对它写入数据

WriteCurrent(add);    //写入指定地址

WriteCurrent(dat);    //写入数据

Stop();    //停止数据传输

Delayms(4);    //一个字节的写入周期为1ms,所以最好延时1ms以上

}

/**从从机的当前地址读取数据**/

Unsigned char ReadCurrent()

{

Unsigned char x;

Start();    //初始化总线

WriteCurrent(OP_READ);   //选择从机并告知要读取数据

X=ReadData();    //将读取的数据存入x

Stop();         //终止数据传输

Return x;    //返回读取数据

}

/**从从机中的某个地址读取数据,set_addr为地址**/

Unsigned char ReadSet(unsigned char set_addr)

{

Start();    //初始化总线

WriteCurrent(OP_WRITE);    //选择从机并告知要写入数据

WriteCurrent(set_addr);    //写入指定地址

return(ReadCurrent());    //从指定地址读取数据并返回

}

/*主函数*/

Main(void)

{

SDA=1;    //使主从设备处于空闲状态

SCL=1;

WriteSet(add,dat);    //例如:在指定地址“0x36”中写入数据“0x0f”

完成其他功能

}