原创 模拟I2C驱动程序,如果觉得好请支持一下!

2008-5-28 12:26 6138 9 11 分类: MCU/ 嵌入式

//=====================================================================================
//  Module Name :  I2C.c
//  CreateDate  :  2008-3-1
//  ModifData   :  2008-3-1
//  Description :  软件模拟I2C驱动程序.参考了周立功模拟I2C(晶振频率要小于12MHZ)
//  Author      :  LuoWei
//  Version     :  V1.0
//=====================================================================================


#include "reg52.h"



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);
}




 

PARTNER CONTENT

文章评论2条评论)

登录后参与讨论

用户485340 2008-9-1 16:04

支持!!

用户461316 2008-8-27 13:16

不错,坚决支持,支持原创作品。
相关推荐阅读
用户1399169 2008-08-16 17:15
电子工程师必上的十大专业网站
在电子产业混,情报能力是相当重要的,具体体现在一要能及早全面地获得最新的设计资讯,二要能认识一些专家级的大虾,当有设计难题时,这些大虾可以伸出热情的手拉你一把,则对你的设计会帮助很大的。小可我在电子产...
用户1399169 2008-07-29 10:31
高速PCB设计指南,喜欢的就收藏吧!
如果你已经设计了足够多的双层板,如果你想往高速PCB方向进军,那么“高速PCB的设计指南”你一定要看!...
用户1399169 2008-07-24 13:04
我的淘宝店
http://shop35826321.taobao.com/本店主营嵌入式开发板,包括单片机开发板,ARM开发板、DSP开发板等,兼营电子元器件及部分接插件。本店承诺,所有开发板均自主研发,如果有质...
用户1399169 2008-06-11 13:48
STC_ISP使用图解
当我们初次使用STC_ISP下载程序时是不是时常出现各种各样的问题呢?这里本人专门写了一个STC_ISP的使用图解,希望能够让初次使用STC_ISP的朋友快速学会STC_ISP的使用,同时也对其他使用...
用户1399169 2008-06-11 13:39
KEIL使用图解-提供给初学者的好东西!
初学者的KEIL快速入门教材!建议:下载时从作到右三个文件分别取名为1、2,之后对1解压缩可以一次性完成!...
我要评论
2
9
关闭 站长推荐上一条 /3 下一条