i2c 总线的时序和读写
#include
#include
#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 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 {
if ((i&0x80)==0)
I2c_Send_Bit(0); //发送0
else
I2c_Send_Bit(1); //发送1
i }
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 {
SCL=0;
delay();
j 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 {
I2c_Start(); //启动I2C
i=Device_Add 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 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 *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 {
if (I2c_Start_Write(Device_Add,Write_Add)==0)
return (0); //启动写模式失败
for (j=0;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 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=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 {
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_Address=2;
if (I2c_Write(2,Write_Add,Read_Add,Block_Size)==0)
{
Lcd_Display(44);
return (0);
}
Wrcs02_Protect_Off();
return (1);
}
//从时钟芯片8583中读取数据
//数据不能全部读出则返回0
byte Read_8583(byte Read_Add,byte *Save_Add,byte Block_Size)
{
byte i;
I2c_Address=1;
if (I2c_Start_Write(1,Read_Add)==0)
return (0); //启动8583写模式失败
if (I2c_Start_Read(1)==0)
return (0); //启动8583读模式失败
if (--Block_Size!=0)
{ //要读取的数据长度不为1
for (i=0;i *Save_Add++=I2c_Receive_Byte1();
}
*Save_Add++=I2c_Receive_Byte2();
I2c_Stop();
return (1);
}
//向时钟芯片8583中写入数据
//数据全部写入返回1,否则返回0
byte Write_8583(byte Write_Add,byte *Read_Add,byte Block_Size)
{
byte i;
I2c_Address=1;
if (I2c_Start_Write(1,Write_Add)==0)
return (0);
for (i=0;i {
if (I2c_Send_Byte(*Read_Add++)==0)
return (0); //发送写入数据后没有回应
}
I2c_Stop();
return (1);
}
//启动8583走时
byte Start_8583_Run(void)
{
byte xdata *px;
*px=0; //32.768kHz
return (Write_8583(0,px,1));
}
//停止8583走时
byte Stop_8583_Run(void)
{
byte xdata *px;
*px=0x80;
return (Write_8583(0,px,1));
}
byte xdata buffer_8583[8]; //用于暂存8583时间数据
//BCD 数转化为二进制数
byte BCD_To_Bin(byte i)
{
byte j;
j=i>>4;
j&=0x0f;
j*=10;
j+=i&0x0f;
return (j);
}
//二进制数转化为BCD 数
byte Bin_To_BCD(byte i)
{
byte j;
j=i/10;
j j&=0xf0;
j|=i%10;
return (j);
}
//设置8583时间
//8583的16-17单元暂存年的低位及高位字节(以二进制方式)
//设置时间不成功则死循环
void Set_8583_Clock(struct RTC_CLOCK *pclock)
{
byte i,j;
Stop_8583_Run(); //停止8583走时
buffer_8583[0]=0x80; //控制字节
buffer_8583[1]=0x55;
buffer_8583[2]=pclock->seconds; //暂存秒
buffer_8583[3]=pclock->minutes; //暂存分
buffer_8583[4]=pclock->hours; //24小时模式
j=BCD_To_Bin(pclock->year_l); //以二进制方式暂存年的低位字节
i=j i&=0xc0;
buffer_8583[5]=i|pclock->day_of_the_month; //年的最低两位+日期
i=pclock->day_of_the_week;
i i&=0xe0;
buffer_8583[6]=i|pclock->months; //星期+月份
if (Write_8583(0,buffer_8583,7)==0)
Lcd_Display(45);
buffer_8583[0]=j;
buffer_8583[1]=BCD_To_Bin(pclock->year_h);
Write_8583(16,buffer_8583,2); //年数据暂存在8583的16-17地址单元内
Start_8583_Run();
}
//读取8583时间
//读取时间不成功则死循环
void Get_8583_Clock(struct RTC_CLOCK *pclock)
{
byte i,j,k;
for (;;)
if (Stop_8583_Run()==1) break;
for (;;)
if (Read_8583(0,buffer_8583,8)==1) break; //从8583地址0 处读出8 字节数据
for (;;)
if (Start_8583_Run()==1) break;
pclock->seconds=buffer_8583[2]; //得到秒
pclock->minutes=buffer_8583[3]; //得到分
pclock->hours=buffer_8583[4]; //得到小时
i=buffer_8583[6];
pclock->months=i&0x1f; //得到月份
i>>=5;
pclock->day_of_the_week=i&0x07; //得到星期
i=buffer_8583[5];
pclock->day_of_the_month=i&0x3f; //得到日期
i=i>>6;
i&=0x03; //得到年的低两位
Read_8583(16,buffer_8583,2); //读取前次存储的年数据
j=buffer_8583[0]; //年的低位字节
k=j&0x03;
if (i!=k)
{ //年值已经改变
if (i>k)
i-=k;
else
i+=4-k;
j+=i; //得到新的年值
if (j>99)
{
j-=100;
buffer_8583[1]++;
}
buffer_8583[0]=j;
Write_8583(16,buffer_8583,2); //年数据暂存在8583的16-17地址单元内
}
pclock->year_l=Bin_To_BCD(j);
pclock->year_h=Bin_To_BCD(buffer_8583[1]);
}