I2C

I2C是英文“Inter   Integrated   Circuit”的缩写,中文意思是“集成电路之间”。总线(Bus)是用来传送信息的公用线。I2C总线就是集成电路之间传送时钟脉冲与数据的公用线 路。采用I2C总线控制就是将微处理器的SCL(串行时钟)、SDA(串行数据)用总线(一根时钟线与一根数据线)与其它集成电路或存储器连接起来,通过 总线来交换信息,实行控制。这样可以减少印制板连接线;而且便于调试与测试;在开发新产品时,由于电路单元可直接在总线上接入和分离,可以很方便地在一个 产品的基础上,完成一系列新产品的开发。 
 
          I2C数据传输的格式是:启动条件   -->   从地址(7bit)   -->   读写(1bit)   -->   确认   -->   子地址(8bit)   -->   确认   -->   传输数据   [n(8bit+确认位)]   -->   停止条件  

  I2C总线传输数据首先要满足启动条件。启动条件是:时钟线(SCL)为高电位时数据线(SDA)由高电位转向低电位。
启动条件通常由微处理器(MPU) 产生。MPU产生启动条件后,接着传送7位二进制数(7bit)组成的“从地址”,所谓“从地址”(即从属地址)就是I2C总线所连接的各集成电路的编号 (二进制数);例如TA8880CN的从地址是1000100、TA8776N的从地址是1000000,不同的集成电路有不同的从地址。MPU若传送从 地址1000100,TA8880CN就接收数据,而TA8776N则不能接收数据。传送从地址之后,传送1bit的读写位;读写位如为“0”,表示 MPU向其他集成电路发送数据,即写入数据;如为“1”表示MPU接收其他集成电路发送的数据,即读入数据。第9位是确认位,此时MPU发送的时钟脉冲 SCL线为高电位,接收数据的集成电路必须把SDA线电位拉低到低电位,才确认接收数据,即传送的数据才有效。接着再传送8bit的“子地址”。所谓“子 地址”,就是在被控制的集成电路中存放各种控制数据的存储单元的地址。例如TA8880CN子地址00000000存放白峰值限幅器及色饱和度控制数据。 子地址00000001存放锐度调整开关与色调控制数据。子地址传送后同样要有确认位。然后一个字节接一个字节地传输数据,每一个字节是8bit长,后面 都要跟随一个确认位,直到MPU发出停止条件为止。停止条件是:当SCL线在高电位时,SDA线由低电位变为高电位。





http://www.21ic.com.cn/pmcu/fxzl/51i2c.htm  
  51单片机模拟I2C总线的C语言实现  
   
   
  电路原理图    
   
     
   
     
  EEPROM为ATMEL公司的AT24C01A。单片机为ATMEL公司的AT89C51。  
   
   
  软件说明    
   
  C语言为Franklin   C   V3.2。将源程序另存为testi2c.c,用命令  
   
  C51   testi2c.c  
   
  L51   TESTI2C.OBJ  
   
  OHS51   TESTI2C  
   
  编译,连接,得到TESTI2C.HEX文件,即可由编程器读入并进行写片,实验。  
   
  3.源程序  
   
  #include   <reg51.h>  
   
  #include   <intrins.h>    
   
  #define   uchar   unsigned   char  
   
  #define   uint   unsigned   int  
   
  #define   AddWr   0xa0   /*器件地址选择及写标志*/  
   
  #define   AddRd   0xa1   /*器件地址选择及读标志*/  
   
  #define   Hidden   0x0e   /*显示器的消隐码*/  
   
  /*有关全局变量*/  
   
  sbit   Sda=   P3^7;   /*串行数据*/  
   
  sbit   Scl=   P3^6;   /*串行时钟*/  
   
  sbit   WP=   P3^5;   /*硬件写保护*/  
   
  void   mDelay(uchar   j)  
   
  {   uint   i;  
  for(;j>0;j--)  
  {   for(i=0;i<125;i--)  
  {;}  
  }  
  }  
   
  /*发送起始条件*/  
   
  void   Start(void)   /*起始条件*/  
   
  {  
   
  Sda=1;  
   
  Scl=1;  
   
  _nop_   ();  
   
  _nop_   ();  
   
  _nop_   ();  
   
  _nop_   ();  
   
  Sda=0;  
   
  _nop_   ();  
   
  _nop_   ();  
   
  _nop_   ();  
   
  _nop_   ();  
   
  }  
   
  void   Stop(void)   /*停止条件*/  
   
  {  
   
  Sda=0;  
   
  Scl=1;  
   
  _nop_   ();  
   
  _nop_   ();  
   
  _nop_   ();  
   
  _nop_   ();  
   
  Sda=1;  
   
  _nop_   ();  
   
  _nop_   ();  
   
  _nop_   ();  
   
  _nop_   ();  
   
  }  
   
  void   Ack(void)   /*应答位*/  
   
  {  
   
  Sda=0;  
   
  _nop_   ();  
   
  _nop_   ();  
   
  _nop_   ();  
   
  _nop_   ();  
   
  Scl=1;  
   
  _nop_   ();  
   
  _nop_   ();  
   
  _nop_   ();  
   
  _nop_   ();  
   
  Scl=0;  
   
  }  
   
  void   NoAck(void)   /*反向应答位*/  
   
  {  
   
  Sda=1;  
   
  _nop_   ();  
   
  _nop_   ();  
   
  _nop_   ();  
   
  _nop_   ();  
   
  Scl=1;  
   
  _nop_   ();  
   
  _nop_   ();  
   
  _nop_   ();  
   
  _nop_   ();  
   
  Scl=0;  
   
  }  
   
  void   Send(uchar   Data)   /*发送数据子程序,Data为要求发送的数据*/  
   
  {  
   
  uchar   BitCounter=8;   /*位数控制*/  
   
  uchar   temp;   /*中间变量控制*/  
   
  do  
   
  {  
   
  temp=Data;  
   
  Scl=0;  
   
  _nop_   ();  
   
  _nop_   ();  
   
  _nop_   ();  
   
  _nop_   ();  
   
  if((temp&0x80)==0x80)/*   如果最高位是1*/  
   
  Sda=1;  
   
  else  
   
  Sda=0;  
   
  Scl=1;  
   
  temp=Data<<1;   /*RLC*/  
   
  Data=temp;  
   
  BitCounter--;  
   
  }while(BitCounter);  
   
  Scl=0;  
   
  }  
   
   
  uchar   Read(void)   /*读一个字节的数据,并返回该字节值*/  
   
  {  
   
  uchar   temp=0;  
   
  uchar   temp1=0;  
   
  uchar   BitCounter=8;  
   
  Sda=1;  
   
  do{  
   
  Scl=0;  
   
  _nop_   ();  
   
  _nop_   ();  
   
  _nop_   ();  
   
  _nop_   ();  
   
  Scl=1;  
   
  _nop_   ();  
   
  _nop_   ();  
   
  _nop_   ();  
   
  _nop_   ();  
   
  if(Sda)   /*如果Sda=1;*/  
   
  temp=temp|0x01;   /*temp的最低位置1*/  
   
  else  
   
  temp=temp&0xfe;   /*否则temp的最低位清0*/  
   
  if(BitCounter-1)  
   
  {   temp1=temp<<1;  
   
  temp=temp1;  
   
  }  
   
  BitCounter--;  
   
  }while(BitCounter);  
   
  return(temp);  
   
  }  
   
   
  void   WrToROM(uchar   Data[],uchar   Address,uchar   Num)  
   
  {  
   
  uchar   i;  
   
  uchar   *PData;  
   
  PData=Data;  
   
  for(i=0;i<Num;i++)  
   
  {  
   
  Start();   /*发送启动信号*/  
   
  Send(0xa0);   /*发送SLA+W*/  
   
  Ack();  
   
  Send(Address+i);   /*发送地址*/  
   
  Ack();  
   
  Send(*(PData+i));  
   
  Ack();  
   
  Stop();  
   
  mDelay(20);  
   
  }  
   
  }  
   
  void   RdFromROM(uchar   Data[],uchar   Address,uchar   Num)  
   
  {  
   
  uchar   i;  
   
  uchar   *PData;  
   
  PData=Data;  
   
  for(i=0;i<Num;i++)  
   
  {  
   
  Start();  
   
  Send(0xa0);  
   
  Ack();  
   
  Send(Address+i);  
   
  Ack();  
   
  Start();  
   
  Send(0xa1);  
   
  Ack();  
   
  *(PData+i)=Read();  
   
  Scl=0;  
   
  NoAck();  
   
  Stop();  
   
  }  
   
  }  
   
  void   main()  
   
  {  
   
  uchar   Number[4]={1,2,3,4};  
   
  WP=   1;  
   
  WrToROM(Number,4,4);   /*将初始化后的数值写入EEPROM*/  
   
  mDelay(20);  
   
  Number[0]=0;  
   
  Number[1]=0;  
   
  Number[2]=0;  
   
  Number[3]=0;   /*将数组中的值清掉,以验证读出的数是否正确*/  
   
  RdFromROM(Number,4,4);  
   
  }  
   
  问题:本程序中未采用块读写的方法,显得有点‘笨’,这是由于项目原因,现项目已完成,程序已写好,短时不会修改,也不会花上一定的精力去做,虽然理论上 已很成熟,就这样写一下,未必不对,但与我的本栏目要求不符,所以就未做上去,如果以后我做了,将再补上。   
   
  欢迎转载,请注明出自平凡的单片机世界  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值