?? i2c 總線的時序和讀寫.txt
字號:
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_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<Block_Size;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<Block_Size;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<<=4;
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<<6;
i&=0xc0;
buffer_8583[5]=i|pclock->day_of_the_month; //年的最低兩位+日期
i=pclock->day_of_the_week;
i<<=5;
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]);
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -