#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”
完成其他功能
}