1.  I2C总线的基本概念
    1)发送器(Transmitter):发送数据到总线的器件
    2)接收器(Receiver):从总线接收数据的器件
    3)主机(Master):初始化发送、产生时钟信号和终止发送的器件
    4)从机(Slave):被主机寻址的器件

2. I2C总线的信号传输

1) 3种速率可选择
    标准模式100kbps、快速模式400kbps、最高速率3.4Mbps
2) 具有特定的传输起始、停止条件
    a) 起始条件:当SCL 处于高电平期间时,SDA 从高电平向低电平跳变时产生起始条件。 起始条件常常简记为S
    b) 停止条件:当SCL 处于高电平期间时,SDA 从低电平向高电平跳变时产生停止条件。 停止条件简记为P

3) 数据传输从确定从机地址开始
    a)多个从机可连接到同一条I2C 总线上,它们之间通过各自唯一的器件地址来区分
    b)一般从机地址由7 位地址位和一位读写标志R/W 组成,7 位地址占据高7 位,读写位在最后。读写位是0,表示主机将要向从机写入数据;读写位是1,则表示主机将要从从机读取数据   
4)  以字节为单位的数据传输方式
    a) I2C 总线以字节(Byte) 为单位收发数据,主机总是先发地址再发数据
    b) 在I2C总线传输数据过程中,每传输一个字节,都要跟一个应答状态位。遵循"谁接收谁产生"的原则,即总是由接收器产生应答位,应答位为0 表示接收器应答 (ACK) ;为1 则表示非应答(NACK)
    c) 如果接收器在接收完最后一个字节的数据,或者不能再接收更多的数据时,应当产生非应答来通知发送器

一次iic交互的例子,写AT24C08

    写AT24C08:
start信号 + addr + data[N] + stop信号
{
. master发送start信号: [scl高+sda下降沿] 2.1. master发送addr: 7位设备地址 + R/W; 发完立刻把电平拉高,等待slave的ack;
[sda在scl低电平的时候准备数据, 在scl上升沿时发送数据] * 8次
MSB---先发最高位数据sda.
2.2. slave收到master的start信号后,就开始监测master的数据了. 收到addr完毕并且发现addr就是自己的时候,马上拉低sda以表明传输有效(这就是所谓ack). 3.1 主机收到ack后接着发送数据data, 这里是写1个字节,那就和发送addr用同样的方法连续发送8个bit就是了.
同样,发完立刻把电平拉高,等待slave的ack;
3.2 slave收到8位data完毕,马上拉低sda以表明传输有效(ack). . master收到ack,马上发送stop信号以关闭通信. 说明:
iic协议允许一次连接中传输多个字节,具体最多允许多少个字节看器件(AT24C08允许8个字节连续传输), 但是必须以8bit为单位, 接收方要给一个ack才会继续后面的传输.
明确start和stop是由master发起的. }
 
I2C总线数据传输时序图示

(灰色为主机的工作时隙,白色为从机的工作时隙)

S:起始位(START)

SA:从机地址(Slave Address),7 位从机地址

W:写标志位(Write),1 位写标志 R:读标志位(Read),1 位读标志

A:应答位(Acknowledge),1 位应答

A:非应答位(Not Acknowledge),1 位非应答

D:数据(Data),每个数据都必须是8 位

P:停止位(STOP)

3. I2C 总线具有如下特点
    1) I2C 总线是双向传输的总线,因此主机和从机都可能成为发送器和接收器。
        不论主机是发送器还是接收器,时钟信号SCL都要由主机来产生。
    2) 读取数据是依据SCL为低时,SDA的电平.
    3) 进行数据传送时,在SCL为高电平期间,SDA线上电平必须保持稳定,只有SCL为低时,才允许SDA线上电平改变状态。并且每个字节传送时都是高位在前。
    4) 关于时钟:
        由于通讯的时钟是由主机(master)控制的, 所以slave不需要有设置工作频率, master快, slave就快, master慢, slave就慢. (甚至可以时快时慢, 忽快忽慢). 但通常会有一个固定频率.
        现在的I2C都是由集成的模块实现, 集成的模块往往能够满足I2C通讯的最大通讯速度, 所以从这个角度考虑, slave是完全不需要考虑通讯频率的.
    5) . 关于应答信号:
    ACK=0时为有效应答位,说明从机已经成功接收到该字节,若为1则说明接受不成功。    
    主机在读取从机数据时,也会产生ack,但是主机读取最后一个字节时不需要产生ack.

6) 只需要由两根信号线组成,一根是串行数据线SDA,另一根是串行时钟线SCL。
    7) SDA 和SCL 信号线都必须要加上拉电阻Rp(Pull-Up Resistor)。上拉电阻一般取值3~ 10KΩ
    8) SDA 和SCL 管脚都是漏极开路(或集电极开路)输出结构
    9) 同一IIC总线上同一型号的IC只能最多共挂8片同种类芯片

4. I2C总线注意点
    1) . 在特殊情况下,若需禁止所有发生在I2C总线上的通信,可采用封锁或关闭总线,具体操作为在总线上的任一器件将SCL锁定在低电平即可。
    2) . 如果从机需要延迟下一个数据字节开始传送的时间,可以通过把SCL电平拉低并保持来强制主机进入等待状态。
    3) . 主机完成一次通信后还想继续占用总线在进行一次通信,而又不释放总线,就要利用重启动信号。它既作为前一次数据传输的结束,又作为后一次传输的开始。
    4) . 总线冲突时,按"低电平优先"的仲裁原则,把总线判给在数据线上先发送低电平的主器件。
    5) . SDA仲裁和SCL时钟同步处理过程没有先后关系,而是同时进行的。

5. I2C总线在手机上的常见应用

  所应用范围包括:摄像头、调频收音机芯片、音频编解码芯片、模拟电视、光电鼠标等

IIC 通讯协议 <http://blog.csdn.net/zmq5411/article/details/6085740>

由时序图写出IIC通信的Master代码, 不咋准确,仅作理解使用:

//准备:
void init() // 初始化
{
SCL=;
delay();
SDA=;
delay();
} /*从下面开始, delay()的主要作用是维护周期.*/ //generate Start signal
void start() // 启动信号
{
SDA=;
delay();
SCL=;
delay();
SDA=;
delay();
}
//generate Stop signal
void stop() // 停止信号
{
SDA=;
delay();
SCL=;
delay();
SDA=;
delay();
}
// ACK
// 个人感觉这个ACK处理的不太好, 半个周期内理想条件下SDA已经置为1,这个时候SCL拉高没有问题. 但如果从机响应较慢呢? 就会形成 SCL=1 + SDA下降沿, 那就形成了一个start信号.
// 如果只是一个slave,这没什么,但是对于带了多个slave的总线,其他slave就进入接收预备状态,不太符合情理.
// 应该在这里可以多等一下,保证主机拉高sda以及从机拉低sda的过程均在SCL=0的时候完成. 即在SCL=1之前再加入delay,并且在SCL=1之前就可以读SDA了,读到ack之后再拉高.
void wait_ack() //等待回应信号
{
uchar i=;
SCL=;
delay(); //这个delay是为了维持半个周期.
while((SDA==)&&(i<)) //slave的ack会将sda拉低. 这里为什么要等255个循环? 是为了等待ack.
{
i++;
}
SCL=; //读到ack之后又拉低SCL, 准备下一个周期
delay();
} // writebyte
void writebyte(uchar date) // 写一个字节
{
uchar i, temp;
temp = date;
for(i=;i<;i++)
{
Temp = temp<<;
SCL = ;
delay();
SDA = CY;
delay();
SCL = ;
delay();
}
SCL = ;
delay(); // 这个delay是为了等待SCL稳定过渡到低电平同时维持半个周期的时间.
SDA = ; // 发完立刻把电平拉高,等待slave的ack;
delay(); // 这个delay是为了维持半个周期的时间.
} //readbyte
uchar readbyte()//读一个字节
{
uchar i, j, k;
SCL=;
delay();
SDA=;
for(i=;i<;i++)
{
SCL=;
delay();
if(SDA==)
j=;
else
j=;
k=(k<<)|j;
SCL=;
delay();
}
delay();
return k;
} // write_add
void write_add(uchar address, uchar info)//指定地址写一个字节数据
{
start();
writebyte(0xa0);//这是一个从机芯片硬件的地址+ /W信号,不同芯片会不一样
wait_ack();//等待应答
writebyte(address);//这是指定从机芯片的内部存储地址
wait_ack();
writebyte(info);
wait_ack();
stop();
} // read_add
uchar read_add(uchar address)//指定地址读一个字节数据
{
uchar dd;
start();
writebyte(0xa0); //这是一个从机芯片硬件的地址+ /W 信号,不同芯片会不一样
wait_ack();
writebyte(address);
wait_ack();
start();
writebyte(0xa1);//这是一个从机芯片硬件的地址+ R信号,不同芯片会不一样
wait_ack();
dd=readbyte();
stop();
return dd;
}

参考:

总线接口与计算机通信(一)I2C总线的更多相关文章

  1. 总线接口与计算机通信(二)SPI总线

    SPI总线协议及SPI时序图详解  : http://blog.163.com/sunshine_linting/blog/static/44893323201181482335951/ 浅谈SPI总 ...

  2. 总线接口与计算机通信(五)CAN总线

        CAN网络图示     CAN的特点      CAN协议具有以下特点.      (1) 多主控制  在总线空闲时,所有的单元都可开始发送消息(多主控制). 最先访问总线的单元可获得发送权( ...

  3. 总线接口与计算机通信(三)UART起止式异步通用串行数据总线

    串口简介 1. 什么是串口? 串口是计算机上一种非常通用的设备通信的协议.串口通信的概念非常简单,串口按位(bit) 发送和接收字节.尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送 ...

  4. 总线接口与计算机通信(四)USB外部总线(初级认识)

    USB简介   USB是英文Universal Serial BUS(通用串行总线)的缩写,是一个外部总线标准,用于规范电脑与外部设备的连接和通讯,是应用在PC领域的接口技术.USB接口支持设备的即插 ...

  5. I2C 总线原理与架构

    一.I2C总线原理 I2C是一种常用的串行总线,由串行数据线SDA 和串行时钟线SCL组成.I2C是一种多主机控制总线,它和USB总线不同,USB是基于master-slave机制,任何设备的通信必须 ...

  6. i2c总线,核心,驱动详解

    Linux I2C驱动分析(一)----I2C架构和总线驱动 一.I2C总线原理 I2C是一种常用的串行总线,由串行数据线SDA 和串线时钟线SCL组成.I2C是一种多主机控制总线,它和USB总线不同 ...

  7. 【转】I2C总线协议

    I2C总线(Inter Integrated-Circuit)是由PHILIPS公司在上世纪80年代发明的一种电路板级串行总线标准,通过两根信号线——时钟线SCL和数据线SDA——即可完成主从机的单工 ...

  8. i2c总线,设备,驱动之间的关系

    ------ 总线上先添加好所有具体驱动,i2c.c遍历i2c_boardinfo链表,依次建立i2c_client, 并对每一个i2c_client与所有这个线上的驱动匹配,匹配上,就调用这个驱动的 ...

  9. Linux设备驱动模型之I2C总线

    一.I2C子系统总体架构 1.三大组成部分 (1)I2C核心(i2c-core):I2C核心提供了I2C总线驱动(适配器)和设备驱动的注册.注销方法,提供了与具体硬件无关的I2C读写函数. (2)I2 ...

随机推荐

  1. r语言之生成规则序列,规则序列函数及用法

    在生成序列时,“:”的优先级最高 (1)从1到20的整数序列: > 1:20 [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 (2) ...

  2. 我的Python成长之路---第七天---Python基础(22)---2016年2月27日(晴)

    socket网络编程 socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. ...

  3. HBase性能测试

    hbase org.apache.hadoop.hbase.PerformanceEvaluationUsage: java org.apache.hadoop.hbase.PerformanceEv ...

  4. Qt中addStretch的有趣应用

    今天在使用addStretch,布局的时候,发现addStretch竟然是可以平均分配的,有意思.比如: QVBoxLayout *buttonLayout = new QVBoxLayout; bu ...

  5. Qt中将QTableView中的数据导出为Excel文件

    如果你在做一个报表类的程序,可能将内容导出为Excel文件是一项必须的功能.之前使用MFC的时候我就写过一个类,用于将grid中的数据导出为Excel文件.在使用了QtSql模块后,我很容易的将这个类 ...

  6. Mybatis 的Log4j日志输出问题 - 以及有关日志的所有问题

    使用Mybatis的时候,有些时候能输出(主要是指sql,参数,结果)日志.有些时候就不能. 无法输出日志的时候,无论怎么配置log4j,不管是properties的还是xml的,都不起作用. 有些时 ...

  7. 物流追踪 - -GPS和GPRS应用

    源码1: #include<stdio.h> #include<stdlib.h> #include<string.h> #include<termios.h ...

  8. 【Hibernate】set排序

    使用hibernate进行一对多操作的时候,普遍使用HashSet进行操作.但是HashSet是无序集合,对此可以使用TreeSet进行排序. 1.将HashSet改为TreeSet private ...

  9. 关于方法中的形参out

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  10. Android:mimeType

    接收从其他应用传过来的数据,要用到清单文件 <activity android:name="com.terry.myActivity2" android:label=&quo ...