I2C模拟

sbit SDA="P1"^7;                   //模拟I2C数据传送位
sbit SCL="P1"^6;                   //模拟I2C时钟控制位

bit ack;                  //应答标志位

//--------------------------------------------------------------------------
//函数名称:      I2C_Delay(uint us)
//函数功能:      用于I2C的us级延时
//其他说明:      无
//--------------------------------------------------------------------------

void I2C_Delay(uint us)
{
    while(--us); 
}


//--------------------------------------------------------------------------
//函数名称:      void I2C_Start()
//函数功能:      起动总线函数 
//其他说明:      启动I2C总线,即发送I2C起始条件.
//--------------------------------------------------------------------------

void I2C_Start(void)
{
    SDA=1;      //发送起始条件的数据信号
    I2C_Delay(1);
    SCL=1;
    I2C_Delay(2);   //起始条件建立时间大于4.7us延时
    SDA=0;      //发送起始信号
    I2C_Delay(2);     
    SCL=0;      //钳住I2C总线,准备发送或接收数据
    I2C_Delay(2);
}


//--------------------------------------------------------------------------      
//函数名称:      void I2C_Stop()
//函数功能:      结束总线函数
//其他说明:      结束I2C总线,即发送I2C结束条件.
//--------------------------------------------------------------------------

void I2C_Stop(void)
{
SDA=0;    //发送结束条件的数据信号
I2C_Delay(1);   //发送结束条件的时钟信号
SCL=1;    //结束条件建立时间大于4μ
I2C_Delay(2);
SDA=1;    //发送I2C总线结束信号
I2C_Delay(2);
}


//--------------------------------------------------------------------------      
//函数名称:      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<   else SDA="0";                
   I2C_Delay(1);
   SCL=1;               //置时钟线为高,通知被控器开始接收数据位
   I2C_Delay(2);        //保证时钟高电平周期大于4u
   SCL=0; 
}

I2C_Delay(1);
SDA=1;                //8位发送完后释放数据线,准备接收应答位
I2C_Delay(1);   
SCL=1;
I2C_Delay(1);
if(SDA==1)ack=0;     
else ack="1";        //判断是否接收到应答信号
SCL=0;
I2C_Delay(1);
}



//--------------------------------------------------------------------------      
//函数名称:      uchar RcvByte();
//函数功能:      字节数据传送函数   
//其他说明:      用来接收从器件传来的数据,并判断总线错误(不发应答信号),发完后请用应答函数。
//--------------------------------------------------------------------------

uchar RcvByte(void)
{
uchar retc;
uchar BitCnt; 
retc=0; 
SDA=1;                //置数据线为输入方式
for(BitCnt=0;BitCnt<8;BitCnt++)
{
   I2C_Delay(1);           
   SCL=0;                  //置时钟线为低,准备接收数据位                
   I2C_Delay(2);    //时钟低电平周期大于4.7u
   SCL=1;                  //置时钟线为高使数据线上数据有效
   I2C_Delay(1);
   retc=retc<<1;
   if(SDA==1)retc=retc+1; //读数据位,接收的数据位放入retc中
   I2C_Delay(1);
}
SCL=0;    
I2C_Delay(1);
return(retc);
}


//--------------------------------------------------------------------------      
//函数名称:      void I2C_Ack(bit a);
//函数功能:      应答子函数
//其他说明:      主控器进行应答信号,(可以是应答或非应答信号)
//--------------------------------------------------------------------------

void I2C_Ack(bit a)
{
if(a==0)SDA=0;           //在此发出应答或非应答信号
else SDA="1";
I2C_Delay(1);     
SCL=1;                   
I2C_Delay(2);     //时钟低电平周期大于4μ
SCL=0;                  //清时钟线,钳住I2C总线以便继续接收
I2C_Delay(1);    
}



//--------------------------------------------------------------------------      
//函数名称:      bit I2C_SendByte(uchar sla,uchar c)
//函数功能:      向无子地址器件发送字节数据函数 
//其他说明:      使用前必须已结束总线。
//--------------------------------------------------------------------------

bit I2C_SendByte(uchar sla,uchar c)
{
I2C_Start();               //启动总线
SendByte(sla);             //发送器件地址
if(ack==0)return(0);
SendByte(c);               //发送数据
if(ack==0)return(0);
I2C_Stop();                //结束总线
return(1);
}


//--------------------------------------------------------------------------      
//函数名称:      bit I2C_SendStr(uchar sla,uchar suba,ucahr *s,uchar no);
//函数功能:      向有子地址器件发送多字节数据函数 
//入口参数:      sla:从器件地址,suba:子地址,*s:指向发送内容,no:发送字节数。
//其他说明:      使用前必须已结束总线,对于at24cXX元件必须加延时,否则出错
//               一次至多只能写入16字节,否则需要翻页
//--------------------------------------------------------------------------

bit I2C_SendStr(uchar sla,uchar suba,uchar *s,uchar no)
{
uchar i;   
I2C_Start();      //启动总线
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++;
} 
I2C_Stop();       //结束总线
I2C_Delay(1000);     //对于at24cXX元件需要加延时 
return(1);

}


//--------------------------------------------------------------------------      
//函数名称:       bit I2C_RcvByte(uchar sla,ucahr *c); 
//函数功能:      向无子地址器件读字节数据函数
//入口参数:      sla:从器件地址,c:返回值
//其他说明:      从启动总线到发送地址,读数据,结束总线的全过程,从器件地址sla,返回值在c.
//--------------------------------------------------------------------------

bit I2C_RcvByte(uchar sla,uchar *c)
{
I2C_Start();                //启动总线
SendByte(sla+1);            //发送器件地址
if(ack==0)return(0);
*c=RcvByte();               //读取数据
I2C_Ack(1);                 //发送非就答位
I2C_Stop();                 //结束总线 
return(1);
}


//--------------------------------------------------------------------------      
//函数名称:      I2C_RcvStr(uchar sla,uchar suba,uchar *s,uchar no)
//函数功能:      向有子地址器件读取多字节数据函数,读出的内容放入s指向的存储区 
//入口参数:      sla:从器件地址,suba:子地址,no:要读的字节数
//其他说明:      无
//--------------------------------------------------------------------------

bit I2C_RcvStr(uchar sla,uchar suba,uchar *s,uchar no)
{
uchar i;
I2C_Start();                  //启动总线
SendByte(sla);                //发送器件地址
if(ack==0)return(0);
SendByte(suba);               //发送器件子地址
if(ack==0)return(0);

I2C_Start();      //重新启动总线
SendByte(sla+1);
if(ack==0)return(0);
for(i=0;i {   
   *s=RcvByte();               //发送数据
   I2C_Ack(0);      //发送就答位 
   s++;
} 
*s=RcvByte();
I2C_Ack(1);                   //发送非应位
// I2C_Delay(10); 
I2C_Stop();                   //结束总线 
return(1);
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值