i2c 总线的时序和读写
#include <w77e58.h>
#include <file.h>
#define I2c_Control 0xa0 //I2C器件控制字节高四位为0x0a
#define Wr2_Address 0xa000
extern bdata byte Yo2_Buf;
extern idata byte TimerOf1ms;
sbit SDA=P1^6;
sbit SCL=P1^7;
//以下是对I2C器件的操作
//SDA及SCL空闲状态均保持高电平
//允许写入24LC01
byte idata I2c_Address;
void Wrcs01_Protect_On(void)
{
byte xdata *px;
px=Wr2_Address;
Yo2_Buf&=0xf3; //允许写入24LC01
*px=Yo2_Buf;
}
//禁止写入24LC01
void Wrcs01_Protect_Off(void)
{
byte xdata *px;
px=Wr2_Address;
Yo2_Buf&=0xf3;
Yo2_Buf|=0x04; //禁止写入24LC01
*px=Yo2_Buf;
}
//允许写入24LC02
void Wrcs02_Protect_On(void)
{
byte xdata *px;
px=Wr2_Address;
Yo2_Buf|=0x0c; //允许写入24LC02
*px=Yo2_Buf;
}
//禁止写入24LC02
void Wrcs02_Protect_Off(void)
{
byte xdata *px;
px=Wr2_Address;
Yo2_Buf&=0xf3;
Yo2_Buf|=0x04; //禁止写入24LC02
*px=Yo2_Buf;
}
void delay(void)
{
byte i,j;
for (i=0;i<2;i++)
j++;
}
//启动I2C器件的读写
void I2c_Start(void)
{
SCL=0;
delay();
SDA=1;
delay();
delay();
SCL=1;
delay();
delay();
SDA=0;
delay();
delay();
}
//停止I2C器件的读写
void I2c_Stop(void)
{
SCL=0;
delay();
SDA=0;
delay();
delay();
SCL=1;
delay();
delay();
SDA=1;
delay();
}
//在SCL的上升沿向I2C总线上发送一位数据
void I2c_Send_Bit(bit b_data)
{
SCL=0;
delay();
SDA=b_data;
delay();
delay();
SCL=1;
delay();
}
//从I2C总线上接收ACK应答信号
//接收到ACK 则返回true,否则返回false
byte I2c_Receive_ACK(void)
{
bit i;
SCL=0;
delay();
SDA=1; //准备接收ACK 应答
delay();
delay();
i=SDA;
SCL=1;
delay();
if (i==0)
return (1);
return (0);
}
//在SCL的下降沿向I2C总线上发送一字节数据,并接收ACK 应答信号
//接收到ACK 则返回1,否则返回0
byte I2c_Send_Byte(byte i)
{
byte j;
for (j=0;j<8;j++)
{
if ((i&0x80)==0)
I2c_Send_Bit(0); //发送0
else
I2c_Send_Bit(1); //发送1
i<<=1;
}
if (I2c_Receive_ACK()==0)
return (0); //收不到应答信号
return (1);
}
//在SCL的下降沿从I2C总线上接收一字节数据
byte I2c_Receive_Byte(void)
{
byte i,j;
SCL=0;
delay();
SDA=1;
for (i=0,j=0;i<8;i++)
{
SCL=0;
delay();
j<<=1;
delay();
if (SDA==1)
j++;
SCL=1;
delay();
}
return (j);
}
//在SCL的下降沿从I2C总线上接收一字节数据,并发送ACK
byte I2c_Receive_Byte1(void)
{
byte i;
i=I2c_Receive_Byte(); //接收一字节数据
I2c_Send_Bit(0); //发送ACK
return (i);
}
//在SCL的下降沿从I2C总线上接收一字节数据,但不发送ACK
byte I2c_Receive_Byte2(void)
{
byte i;
i=I2c_Receive_Byte(); //接收一字节数据
I2c_Send_Bit(1); //不发送ACK
return (i);
}
//启动I2C器件写操作模式
//Device_Add--I2C器件地址
//address--数据要写入的地址
//成功返回1,否则返回0
byte I2c_Start_Write(byte Device_Add,byte address)
{
byte i,j;
for (j=0;j<3;j++)
{
I2c_Start(); //启动I2C
i=Device_Add<<1;
i|=I2c_Control; //加入控制码
i&=0xfe; //写操作
if (I2c_Send_Byte(i)==1)
{ //发送控制字节后有正确应答
if (I2c_Send_Byte(address)==1)
return (1); //发送写地址后有应答
}
I2c_Stop(); //结束I2C器件的读写
TimerOf1ms=4;
for (;;)
if (TimerOf1ms==0) break; //延时4 毫秒后再次重试
}
switch (I2c_Address)
{
case 0: Lcd_Display(38);break;
case 1: Lcd_Display(39);break;
case 2: Lcd_Display(40);
}
return (0);
}
//启动I2C器件读操作模式
//Device_Add--I2C器件地址
//成功返回1,否则返回0
byte I2c_Start_Read(byte Device_Add)
{
byte i;
I2c_Start(); //再次启动I2C
i=Device_Add<<1;
i|=I2c_Control; //加入控制码
i|=0x01; //读操作
if (I2c_Send_Byte(i)==0)
return (0); //发送控制字节后没有应答
return (1);
}
//从I2C器件中读取数据
//device_add--器件地址(0-24LC01,1-8583,2-24LC02)
//read_add--读数据的起始地址
//save_add--读出的数据的存储地址
//block_size--要读取的数据的长度
//数据全部读出则返回1,否则返回0
byte I2c_Read(byte Device_Add,byte Read_Add,byte *Save_Add,byte Block_Size)
{
byte i;
if (I2c_Start_Write(Device_Add,Read_Add)==0)
return (0); //启动写模式失败
if (I2c_Start_Read(Device_Add)==0)
return (0); //启动读模式失败
if (--Block_Size!=0)
{ //要读取的数据长度不为1
for (i=0;i<Block_Size;i++)
*Save_Add++=I2c_Receive_Byte1();
}
*Save_Add++=I2c_Receive_Byte2();
I2c_Stop();
return (1);
}
//向I2C 器件中某一页面写入数据
byte I2c_Write_Page(byte Device_Add,byte Write_Add,byte *Read_Add,byte Size)
{
byte i,j;
byte xdata temp[8];
for (i=0;i<3;i++)
{
if (I2c_Start_Write(Device_Add,Write_Add)==0)
return (0); //启动写模式失败
for (j=0;j<Size;j++)
{
if (I2c_Send_Byte(Read_Add[j])==0)
return (0); //发送写入数据后没有回应
}
I2c_Stop();
if (I2c_Read(Device_Add,Write_Add,temp,Size)==1) //将刚刚写入的一页读出
{
for (j=0;j<Size;j++)
if (Read_Add[j]!=temp[j]) break; //读出的数据与写入的不同
if (j==Size)
break; //数据已经被正确写入则退出循环,否则再次写入
}
else
return (0);
}
if (i==3)
return (0); //三次写入不正确
return (1);
}
//向I2C器件中写入数据
//device_add--器件地址(0-24LC01、1-8583、2-24LC02)
//Save_add--要写入数据的起始地址
//Read_add--读出的数据的存储地址
//block_size--要写入的数据的长度
//数据全部读出则返回1,否则返回0
byte I2c_Write(byte Device_Add,byte Write_Add,byte *Read_Add,byte Block_Size)
{
byte i,j;
j=Write_Add&0x07;
if (j!=0)
{
j=8-j; //本页面还可写入的数据长度
if (Block_Size<j)
j=Block_Size; //要写入的数据总长度小于本页面还可写入的数据长度
if (I2c_Write_Page(Device_Add,Write_Add,Read_Add,j)==0)
return (0);
Write_Add+=j;
Read_Add+=j;
Block_Size-=j; //还需读出的数据的长度
}
if (Block_Size!=0)
{ //还有数据需要读出
j=Block_Size/8;
if (j!=0)
{
for (i=0;i<j;i++)
{
if (I2c_Write_Page(Device_Add,Write_Add,Read_Add,8)==0)
return (0);
Write_Add+=8;
Read_Add+=8;
}
}
j=Block_Size%8;
if (j!=0)
{
if (I2c_Write_Page(Device_Add,Write_Add,Read_Add,j)==0)
return (0);
}
}
I2c_Stop();
return (1);
}
//从24LC01中读取数据
//Read_Add--要读取数据的首地址
//Save_Add--读出数据的存储地址
//Block_Size--要读数据的长度
//数据不能全部读出则死循环
byte Cs01_Read(byte Read_Add,byte *Save_Add,byte Block_Size)
{
I2c_Address=0;
if (I2c_Read(0,Read_Add,Save_Add,Block_Size)==0)
{
Lcd_Display(41);
return (0);
}
return (1);
}
//向24LC01中写入数据
//Write_Add--要写入的首地址
//Read_Add--要写入数据的读取地址的首地址
//Block_Size--要写入数据的长度
//数据不能全部写入则死循环
byte Cs01_Write(byte Write_Add,byte *Read_Add,byte Block_Size)
{
Wrcs01_Protect_On();
I2c_Address=0;
if (I2c_Write(0,Write_Add,Read_Add,Block_Size)==0)
{
Lcd_Display(42);
return (0);
}
Wrcs01_Protect_Off();
return (1);
}
//从24LC02中读取数据
byte Cs02_Read(byte Read_Add,byte *Save_Add,byte Block_Size)
{
I2c_Address=2;
if (I2c_Read(2,Read_Add,Save_Add,Block_Size)==0)
{
Lcd_Display(43);
return (0);
}
return (1);
}
//向24LC02中写入数据
byte Cs02_Write(byte Write_Add,byte *Read_Add,byte Block_Size)
{
Wrcs02_Protect_On();
I2c_Addre