留意:一般M51单片机机器周期=12个时钟周期,f020机器周期=时钟周期
关于nop指令,F020是一个时钟周期,例如f020晶振为22.1184M, 约为45ns
/*函数是选用软件延时的办法发生SCL脉冲,固对高晶振频率要作 必定的修正….(本软件包是1us机器周期,即晶振频率要小于12MHZ)总线时序契合I2C规范形式,100Kbit/S。*/
#include
#include
#define uchar unsigned char /*宏界说*/
#define uint unsigned int
#define _Nop() _nop_() /*界说空指令1us*/
sbit SDA=P3^4; /*模仿I2C数据传送位*/
sbit SCL=P3^5; /*模仿I2C时钟操控位*/
bit ack; /*应对标志位*/
/*******************************************************************
起动总线函数
函数原型: void Start_I2c();
功用: 发动I2C总线,即发送I2C开端条件.
********************************************************************/
void Start_I2c()
{
SDA=1; /*发送开端条件的数据信号*/
_Nop();
SCL=1;
_Nop(); /*开端条件树立时刻大于4.7us,延时*/
_Nop();
_Nop();
_Nop();
_Nop();
SDA=0; /*发送开端信号*/
_Nop(); /* 开端条件确定时刻大于4μs*/
_Nop();
_Nop();
_Nop();
_Nop();
SCL=0; /*钳住I2C总线,预备发送或接纳数据 */
_Nop();
_Nop();
}
/*******************************************************************
完毕总线函数
函数原型: void Stop_I2c();
功用: 完毕I2C总线,即发送I2C完毕条件.
********************************************************************/
void Stop_I2c()
{
SDA=0; /*发送完毕条件的数据信号*/
_Nop(); /*发送完毕条件的时钟信号*/
SCL=1; /*完毕条件树立时刻大于4μs*/
_Nop();
_Nop();
_Nop();
_Nop();
_Nop();
SDA=1; /*发送I2C总线完毕信号*/
_Nop();
_Nop();
_Nop();
_Nop();
}
/*******************************************************************
字节数据发送函数
函数原型: void SendByte(uchar c);
功用: 将数据c发送出去,可所以地址,也可所以数据,发完后等候应对,并对
此状况位进行操作.(不应对或非应对都使ack=0)
发送数据正常,ack=1; ack=0表明被控器无应对或损坏。
********************************************************************/
void SendByte(uchar c)
{
uchar BitCnt;
for(BitCnt=0;BitCnt<8;BitCnt++) /*要传送的数据长度为8位*/
{
if((c<
_Nop();
SCL=1; /*置时钟线为高,告诉被控器开端接纳数据位*/
_Nop();
_Nop(); /*确保时钟高电平周期大于4μs*/
_Nop();
_Nop();
_Nop();
SCL=0;
}
_Nop();
_Nop();
SDA=1; /*8位发送完后开释数据线,预备接纳应对位*/
_Nop();
_Nop();
SCL=1;
_Nop();
_Nop();
_Nop();
if(SDA==1)ack=0;
else ack=1; /*判别是否接纳到应对信号*/
SCL=0;
_Nop();
_Nop();
}
/*******************************************************************
字节数据接纳函数
函数原型: uchar RcvByte();
功用: 用来接纳从器材传来的数据,并判别总线过错(不发应对信号),
发完后请用应对函数应对从机。
********************************************************************/
uchar RcvByte()
{
uchar retc;
uchar BitCnt;
retc=0;
SDA=1; /*置数据线为输入方法*/
for(BitCnt=0;BitCnt<8;BitCnt++)
{
_Nop();
SCL=0; /*置时钟线为低,预备接纳数据位*/
_Nop();
_Nop(); /*时钟低电平周期大于4.7μs*/
_Nop();
_Nop();
_Nop();
SCL=1; /*置时钟线为高使数据线上数据有用*/
_Nop();
_Nop();
retc=retc<<1;
if(SDA==1)retc=retc+1; /*读数据位,接纳的数据位放入retc中 */
_Nop();
_Nop();
}
SCL=0;
_Nop();
_Nop();
return(retc);
}
/********************************************************************
应对子函数
函数原型: void Ack_I2c(bit a);
功用: 主控器进行应对信号(可所以应对或非应对信号,由位参数a决议)
********************************************************************/
void Ack_I2c(bit a)
{
if(a==0)SDA=0; /*在此宣布应对或非应对信号 */
else SDA=1;
_Nop();
_Nop();
_Nop();
SCL=1;
_Nop();
_Nop(); /*时钟低电平周期大于4μs*/
_Nop();
_Nop();
_Nop();
SCL=0; /*清时钟线,钳住I2C总线以便持续接纳*/
_Nop();
_Nop();
}
/*******************************************************************
用户接口函数
*******************************************************************/
/*******************************************************************
向无子地址器材发送字节数据函数
函数原型: bit ISendByte(uchar sla,ucahr c);
功用: 从发动总线到发送地址,数据,完毕总线的全过程,从器材地址sla.
假如回来1表明操作成功,不然操作有误。
留意: 运用前有必要已完毕总线。
********************************************************************/
bit ISendByte(uchar sla,uchar c)
{
Start_I2c(); /*发动总线*/
SendByte(sla); /*发送器材地址*/
if(ack==0)return(0);
SendByte(c); /*发送数据*/
if(ack==0)return(0);
Stop_I2c(); /*完毕总线*/
return(1);
}
/*******************************************************************
向有子地址器材发送多字节数据函数
函数原型: bit ISendStr(uchar sla,uchar suba,ucahr *s,uchar no);
功用: 从发动总线到发送地址,子地址,数据,完毕总线的全过程,从器材
地址sla,子地址suba,发送内容是s指向的内容,发送no个字节。
假如回来1表明操作成功,不然操作有误。
留意: 运用前有必要已完毕总线。
********************************************************************/
bit ISendStr(uchar sla,uchar suba,uchar *s,uchar no)
{
uchar i;
Start_I2c(); /*发动总线*/
SendByte(sla); /*发送器材地址*/
if(ack==0)return(0);
SendByte(suba); /*发送器材子地址*/
if(ack==0)return(0);
for(i=0;i
SendByte(*s); /*发送数据*/
if(ack==0)return(0);
s++;
}
Stop_I2c(); /*完毕总线*/
return(1);
}
/*******************************************************************
向无子地址器材发送多字节数据函数
函数原型: bit ISendStr(uchar sla,ucahr *s,uchar no);
功用: 从发动总线到发送地址,子地址,数据,完毕总线的全过程,从器材
地址sla,发送内容是s指向的内容,发送no个字节。
假如回来1表明操作成功,不然操作有误。
留意: 运用前有必要已完毕总线。
********************************************************************/
bit ISendStrExt(uchar sla,uchar *s,uchar no)
{
uchar i;
Start_I2c(); /*发动总线*/
SendByte(sla); /*发送器材地址*/
if(ack==0)return(0);
for(i=0;i
SendByte(*s); /*发送数据*/
if(ack==0)return(0);
s++;
}
Stop_I2c(); /*完毕总线*/
return(1);
}
/*******************************************************************
向无子地址器材读字节数据函数
函数原型: bit IRcvByte(uchar sla,ucahr *c);
功用: 从发动总线到发送地址,读数据,完毕总线的全过程,从器材地
址sla,回来值在c.
假如回来1表明操作成功,不然操作有误。
留意: 运用前有必要已完毕总线。
********************************************************************/
bit IRcvByte(uchar sla,uchar *c)
{
Start_I2c(); /*发动总线*/
SendByte(sla+1); /*发送器材地址*/
if(ack==0)return(0);
*c=RcvByte(); /*读取数据*/
Ack_I2c(1); /*发送非就答位*/
Stop_I2c(); /*完毕总线*/
return(1);
}
/*******************************************************************
向有子地址器材读取多字节数据函数
函数原型: bit ISendStr(uchar sla,uchar suba,ucahr *s,uchar no);
功用: 从发动总线到发送地址,子地址,读数据,完毕总线的全过程,从器材
地址sla,子地址suba,读出的内容放入s指向的存储区,读no个字节。
假如回来1表明操作成功,不然操作有误。
留意: 运用前有必要已完毕总线。
********************************************************************/
bit IRcvStr(uchar sla,uchar suba,uchar *s,uchar no)
{
uchar i;
Start_I2c(); /*发动总线*/
SendByte(sla); /*发送器材地址*/
if(ack==0)return(0);
SendByte(suba); /*发送器材子地址*/
if(ack==0)return(0);
Start_I2c(); /*重新发动总线*/
SendByte(sla+1);
if(ack==0)return(0);
for(i=0;i
*s=RcvByte(); /*发送数据*/
Ack_I2c(0); /*发送就答位*/
s++;
}
*s=RcvByte();
Ack_I2c(1); /*发送非应位*/
Stop_I2c(); /*完毕总线*/
return(1);
}
/*******************************************************************
向无子地址器材读取多字节数据函数
函数原型: bit ISendStrExt(uchar sla,ucahr *s,uchar no);
功用: 从发动总线到发送地址,读数据,完毕总线的全过程.
从器材地址sla,读出的内容放入s指向的存储区,
读no个字节。假如回来1表明操作成功,不然操作有误。
留意: 运用前有必要已完毕总线。
********************************************************************/
bit IRcvStrExt(uchar sla,uchar *s,uchar no)
{
uchar i;
Start_I2c();
SendByte(sla+1);
if(ack==0)return(0);
for(i=0;i
*s=RcvByte(); /*发送数据*/
Ack_I2c(0); /*发送就答位*/
s++;
}
*s=RcvByte();
Ack_I2c(1); /*发送非应位*/
Stop_I2c(); /*完毕总线*/
return(1);
}