• IIC通信协议


    IIC

    目录

    IIC

    IIC简介

    IIC的物理层

    IIC主要特点

    IIC的高阻态

    IIC地址

    主机地址

    从机地址

    从机地址规定

    IIC器件地址

    IIC协议

    软件模拟IIC

    IIC数据发送


    IIC简介

    IIC总线是一种由NXP公司开发的两线式串行总线,用于连接微控制器及其外围设备。多用于主控制器和从器件间的主从通信,在小数据量场合使用,传输距离短,任意时刻只能有一个主机。

    在CPU与被控IC之间、IC与IC之间进行双向传送,通信速率一般在100kHZ-400kHZ(48.8kb/s),高速IIC总线一般可达400kbps以上。IIC是为了与低速设备通信而发明的,所以IIC的传输速率比不上SPI。

     

    IIC的物理层

    IIC一共只有两个总线,一条是双向的串行数据线SDA,一条是串行时钟线SCL。

    SDA数据线:用来传输数据的

    SCL时钟线:用来控制数据发送的时序的

    所有接到IIC总线设备上的串行数据SDA都接到总线的SDA上,各设备的SCL都接到总线的SCL上。IIC总线上的每个设备都有自己唯一的地址,来确保不同设备间访问的准确性。

    IIC主要特点

    通信方式有异步和同步通信,IIC是同步通信。

    异步:发送方要等接收方响应才继续通信,阻塞的通信方式

    同步:不用管接收方是否有回应,是非阻塞的通信方式

    通常为了方便把IIC设备分为主设备和从设备,基本上谁控制时钟线(即控制SCL时钟线的电平高低转换)谁就是主设备

    IIC主设备功能:主要产生时钟,产生起始信号和停止信号

    IIC从设备功能:可编程的IIC地址检测,停止位检测

    IIC的一个优点是它支持多主控,其中任何一个能够进行发送和接收的设备都可以成为主总线。一个主控能够控制信号的传输和时钟频率。在任何时间点只能有一个主控。

    SCL和SDA都需要接上拉电阻保证数据的稳定性,减少干扰

    IIC是半双工通信,同一时间只可以单向通信

    为了避免总线信号的混乱,要求各设备连接到总线的输出端时必须是漏极电路(OD)输出或集电极开路输出(OC)。

    IIC的高阻态

    漏极电路(Open Drain)即高阻状态,适用于输入/输出,其可独立输入/输出低电平和高阻状态,若需要产生高电平,则需使用外部上拉电阻。

    高阻状态:高阻状态是三态门电路的一种状态,逻辑门的输出有高低电平两种状态外,还有高阻状态的门电路。高阻态相当于隔断状态。三态门都有一个EN控制使能端来控制门电路的通断。处于高阻态的三态门是与总线隔离开的,这样总线可以同时被其他电路占用。EN=0时,Y为高阻状态。

    IIC的所有设备是连接在一根总线上的,那么进行通信的时候往往只是几个设备进行通信,那这时候其余空闲的设备可能会受到总线干扰,或者干扰到总线。

    为了避免总线信号的混乱,IIC的空闲状态只能有外部上拉,而此时空闲设备被拉到了高阻态,也就是相当于断路,整个IIC总线只有开启了的设备才会正常进行通信,而不会干扰到其他设备。

    IIC地址

    主机地址

    可随意设置,从设备必须配置地址

    从机地址

    IIC从地址有三种类型,7位、8位和10位,厂商采用不同的地址约定。

    7位寻址,如下图oled写入模式的从机地址

    IIC总线规范规定,标准模式从机地址为7位长,其次是读写位。

    在7位寻址过程中,从机地址在启动信号后的第一个字节开始传输,该字节的前7位为从机地址,第8位为读写位,0表示写,1表示读,它决定了传输的方向,第一个字节的第8位是0,表示主机会写信息到被选中的从机。

    从机地址规定

    任何IIC设备都必须遵循这个标准,USB2xxx传输的从机地址即为这7bit地址,不含读写位,读写位会根据不同的函数自动添加进去。

    保留地址:IIC规范保留了两组和8个地址,1111xxx和0000xxx。

    这些地址用于特殊用途。

    8位地址

    一些厂商在提供从机地址的时候说的是包含了读写位的8bit地址,比如他说写地址为0x92,读地址为0x93,8位寻址的情况下需要将这个地址的前7bit提取出来,然后传入USB2xxx的接口函数,如图

    判断厂商提供的地址是7bit模式地址还是8bit地址的方式:7bit地址模式下,地址的取值范围是0x07-0x78,超过了可能就是8bit。

    10位寻址

    IIC总线的10bit寻址和7bit寻址是兼容的,这样就可以在同一个总线上同时使用7bit地址和10bit地址模式的设备,在10bit寻址模式中,从机地址由7个有效位和3个可选位组成。有效位用于指定从机的地址,而可选位则用于扩展寻址范围。

    在IIC总线上,主机发送起始位和读/写位后,紧接着发送7个有效位来指定从机地址。如果需要使用10位寻址模式,则在发送完7个有效位后,再发送3个可选位。

    通过10位寻址模式,可以支持更多的从机地址,扩展了总线上可连接的设备数量。不过不是所有的设备都支持10位寻址模式,所以在使用时需要查看设备的规格说明书来确定支持的寻址模式。

    IIC器件地址

    每一个IIC器件都有一个器件地址,有的器件地址在出厂时地址就设定好了,用户不可以更改。有的器件例如EEPROM,前四个地址已经确定为1010,后三个地址由硬件链接确定的,所以IIC总线最多能连8个EEPROM芯片。

    IIC总线最多可以挂多少个设备:有IIC地址决定,8位地址,减去一位广播地址,2^7=128,0x00不用,所以理论上可以挂127个从器件。

    但是  IIC协议虽然没有规定总线设备最大数目,但是规定了总线电容不能超过400pF。管脚都是有输入电容的,PCB上也会有寄生电容,所以会有一个限制,有人测验大概是不超过8个器件。

    IIC协议

    总线时序图

    初始(空闲)状态:SCL和SDA都保持高电平

    起始信号:SCL为高电平,SDA由高电平变为低电平,数据开始发送

    结束信号:SCL为高电平,SDA由低电平变为高电平,数据传送结束

    有效的数据位传输:在IIC总线上传送的每一位数据都有一个时钟脉冲相对应(或同步控制),即在SCL串行时钟的配合下,数据在SDA上从高位向低位依次串行传送每一位数据。

    应答信号:发送器每发送一个字节(8个bit),就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。

    应答信号为低电平时,规定为有效应答位(ACK,简称应答位),表示接收器已经成功地接收了该字节。

    应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。

    软件模拟IIC

    初始(空闲)状态

    1. void IIC_Init()
    2. {  
    3.     scl = 1;
    4.     delay_us(5);
    5.     sda = 1;
    6.     delay_us(5);
    7. }

    起始信号:SCL保持高电平,SDA由高电平(>4.7us)变为低电平(>4us),SCL变为低电平。

    1. //起始信号
    2. void IIC_Start()
    3. {
    4.     scl = 1;
    5.     sda = 1;
    6.     delay_us(5);
    7.     sda = 0;
    8.     delay_us(5);
    9.     scl = 0;
    10. }

    结束信号:SCL保持高电平(>4us),SDA由低电平变为高电平(>4.7us),SDA变为低电平

    1. //结束信号
    2. void IIC_Stop()
    3. {
    4.     scl = 1;
    5.     sda = 0;
    6.     delay_us(5);
    7.     sda = 1;
    8.     delay_us(5);
    9.     sda = 0;
    10. }

    数据有效性

    IIC信号在数据传输中,当SCL=1高电平时,数据线SDA必须保持稳定状态,不允许有电平跳变,只有在时钟线上的信号为低电平期间,数据线上的电平状态才允许变化。

    SCL=1时,数据线任何的电平状态变换会看做是总线的起始信号或者终止信号。所以在传输数据的过程中,SCL时钟线会频繁的转换电平以保证数据的稳定传输。

    应答信号:主机SCL拉高,读取从机SDA的电平,为低电平表示产生应答

    每发送一个字节(8个bit),在一个字节传输的8个时钟后的第九个时钟期间,接收器接收数据后必须返回一个ACK应答信号给发送器,这样才能进行数据传输。

    1. //应答
    2. void IIC_ACK()
    3. {
    4.     scl = 0;
    5.     sda = 0;
    6.     delay_us(1);
    7.     scl = 1;
    8.     delay_us(5);
    9.     scl = 0;
    10. }
    1. //非应答
    2. void IIC_NACK()
    3. {
    4.     scl = 0;
    5.     sda = 1;
    6.     delay_us(1);
    7.     scl = 1;
    8.     delay_us(5);
    9.     scl = 0;
    10. }

    1. //应答信号sda为低电平,非应答为高电平
    2. //所以读取SDA的状态来判断是什么信号
    3. void IIC_read_ACK()
    4. {
    5.     char flag;//标志位,记录sda的状态
    6.     sda = 1;//在时钟脉冲9期间释放数据线
    7.     delay_us(2);
    8.     scl = 1;
    9.     delay_us(5);
    10.     flag = sda;//在这个期间记录下sda的电平状态
    11.     delay_us(5);
    12.     scl = 0;
    13. return flag;
    14. }

    IIC数据发送

    数据传送时,先传送最高位(MSB),每一个被传送的字节后面都必须跟随一位应答位(即一帧共有9位)。

    当一个字节按数据位从高到低的顺序传输完成后,紧接着从设备将拉低SDA线,回传给主设备一个应答位ACK,此时才认为一个字节真正的被传输完成,如果一段时间内没有收到从机的应答信号,则自动认为从机已正确接收到数据。

    IIC写数据

    IIC的每一帧数据由9bit组成

    如果是发送数据,则包含8bit数据+1bitACK

    如果是设备地址数据,则包含7bit设备地址+1bit方向位+1bitACK

    IIC总线数据格式:

    IIC写数据:

    1. //在SCL为高电平期间,发送数据,发送8次,,数据从高到低
    2. //传输期间保持传输稳定,数据线仅可以在SCL为低电平时改变
    3. void IIC_Write_Byte(chra dataSend)
    4. {
    5.     int i;
    6.     for(i = 0;i < 8;i++){
    7.         //拉低时钟开始数据传输
    8.         scl = 0;
    9.         //获取最高位给sda
    10.         sda = dataSend & 0x80;//1000 0000获得dataSend最高位
    11.         delay_us(5);//发送数据建立时间
    12.         scl = 1;//拉高时钟开始数据发送
    13.         delay_us(5);
    14.         scl = 0;//发送完毕拉低
    15.         delay_us(5);//准备下一个数据位
    16.         dataSend = dataSend << 1;//从高到低发送,左移获得下一位数据
    17.     }
    18. }

    主机向从机发送数据时:

    1. 主机产生start信号
    2. 发送从机地址,第8位数据方向位为0,表明主机要发送数据
    3. 主机发送地址时,总线上的每个从机都将这7位地址码与自己的地址进行比较,若相同,则认为自己正在被主机寻址,根据R/T位将自己确定为接收器
    4. 这时主机就等待从机的应答信号
    5. 当主机接收到应答信号后,发送要访问的从机的寄存器地址,然后等待从机的应答信号
    6. 当主机收到应答信号,发送n个字节的数据,继续等待从机的n次应答信号
    7. 主机产生停止信号,结束传送过程

    IIC读数据

    1. //读数据
    2. void IIC_Read_Byte()
    3. {
    4.     int i,value = 0;
    5.     delay_us(1);
    6.     for(i = 0;i < 8;i++){
    7.         value <<= 1;
    8.         scl = 1;
    9.         delay_us(1);
    10.         if(sda = 1){
    11.             value++;
    12.         }
    13.         delay_us(1);
    14.         scl = 0;
    15.         delay_us(1);
    16.     }
    17.     return value;
    18. }

    主机从 从机读数据时:

    1. 主机产生start信号
    2. 发送从机地址,此时该地址第8位为0,表示向从机写命令
    3. 主机等待从机的应答信号ACK
    4. 主机收到应答信号时,发送要访问的地址,继续等待从机的应答信号
    5. 当主机收到应答信号后,主机要改变通信模式。(主机由发送变为接收,从机由接收变为传送)所以主机重新发送一个开始start信号,然后发送从机地址,这时该地址的第8位为1,表明将主机设置为接收模式开始读数据。
    6. 然后主机等待从机的应答信号,当主机收到应答信号时,就可以接收1个字节的数据,当接收完成后,主机发送非应答信号,表示不再接收数据。
    7. 主机进而产生停止信号,结束传送过程。

  • 相关阅读:
    Knockoutjs属性绑定(Bindings)之流程控制(Control flow)
    剑指 Offer 14- I. 剪绳子
    阿里云CDN加速器基本概念与购买开通
    MYSQL的多版本并发控制MVCC(Multi-Version Concurrency Control)
    网络与信息安全基础知识-- Internet及应用
    Pyecharts绘制动态地图
    使用SPDK lib搭建自己的NVMe-oF Target应用
    ROS2机器人-C++和Python怎么选
    Spring JDBC(配置数据源,操作数据库)
    NSS [GWCTF 2019]枯燥的抽奖
  • 原文地址:https://blog.csdn.net/qq_58264156/article/details/133466920