问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

嵌入式通信协议:IIC简明学习笔记

创作时间:
作者:
@小白创作中心

嵌入式通信协议:IIC简明学习笔记

引用
CSDN
1.
https://m.blog.csdn.net/weixin_73867577/article/details/143313061

IIC(Inter-Integrated Circuit)是一种常用的串行通信协议,广泛应用于嵌入式系统中。本文将简要介绍IIC协议的特点、物理层和协议层,并重点讲解其信号传输过程。

IIC特点

  1. 适合小数据场合使用,传输距离短。
  2. 只能有一个主机。
  3. 标准IIC速度为100kHz,高速IIC一般可达400kHz以上。
  4. SCL和SDA都需要接上拉电阻(大小由速度和容性负载决定,一般在3.3k-10k之间)。
  5. IIC为半双工通信。
  6. 为了避免总线信号混乱,要求各设备连接到总线的输出端时必须是漏极开路(OD)输出或者集电极开路(OC)输出。

IIC物理层

  1. IIC有一条双向的串行数据线SDA,一条串行时钟线SCL。谁控制时钟线谁就是主设备。
  2. 每个设备都有唯一的地址,有的器件地址出厂时就已经设定好。
  3. 漏极开路(OD)即高阻状态,适用于输入/输出,其可独立输入/输出低电平和高阻状态,若需要产生高电平,则需要使用外部上拉电阻。
  4. 总线空闲时,SCL和SDA被上拉电阻拉高,保持高电平。

IIC协议层

IIC在传输过程中有三种信号,分别是开始信号、结束信号和应答信号。

  • 开始信号:SCL为高电平时,SDA由高电平向低电平跳变,开始传输数据。
  • 结束信号:SCL为高电平时,SDA由低电平向高电平跳变,结束传输数据。
  • 应答信号:接收数据的设备在收到8bit数据后,向发送数据的设备发出特定的低电平脉冲,表示已收到数据。CPU向受控单元发出一个信号后,等待受控设备发出一个应答信号,CPU接收到应答信号后,根据实际情况作出是否继续传递信号的判断,若未收到应答信号,则判断受控设备故障。

起始信号是必需的,结束信号和应答信号可以不用。

IIC总线时序图

以下是IIC的通信协议流程:

  1. 初始状态
    SCL和SDA都接上拉电阻,保持空闲状态的稳定性,所以空闲状态下均为高电平。

  2. 开始信号
    SCL保存高电平,SDA由高电平变为低电平后,延时(大于4.7us),SCL变为低电平。

  3. 停止信号
    SCL为高电平,SDA由低电平到高电平。

  4. 数据有效性
    IIC信号在数据传输过程中,当SCL为高电平时,SDA必须保持稳定状态,不允许有电平跳变,只有当SCL为低电平时,数据线才允许高低电平变化。SCL为高电平时,数据线SDA的任何电平变化都会被看做是总线的起始信号或者停止信号。

  5. 应答信号
    每当主机向从机发送完一个字节的数据后,主机总是需要等待从机给出一个应答信号,以确认从机是否接收到了数据。主机SCL拉高(大于4us),读取从机SDA的电平,如果为低电平,则产生应答。应答信号为低电平时,规定为有效应答为(ACK),表示接收器件已经成功接收到了这个字节。若应答信号为高电平,则是非应答位,表示失败接收。

  6. 数据传输
    IIC信号在数据传输过程中,当SCL为高电平时,SDA必须保持稳定状态,不允许有电平跳变,只有当SCL为低电平时,数据线才允许高低电平变化。数据传输图。输出到SDA上的字节必须是8位,数据传输时先传最高位(MSB),每个被传输的字节后面必须跟着一位应答位,也就是说,一帧有9位。当一个字节按数据位从高位到低位的顺序传输完,紧接着从设备拉低SDA线,回传给主设备一个应答位ACK,此时才认为一帧数据才被传输完成。如果一段时间内未收到从机的应答信号,则自动认为从机已经正确接收到了数据。每一帧数据共有9bit。如果是设备地址数据,则包含7bit设备地址+1bit读写位+1位应答位。如果是发送数据,则包含8bit数据+1bit应答位。多数从设备的地址位7位或者10位。8位设备地址=7位从机地址+读/写地址。地址帧中的第8位为读/写位。0表示写数据。1表示读数据。向7位地址设备写数据。向7位地址设备读数据。向10位地址设备写数据。向10位地址设备读数据。

IIC信号传输过程

开始信号

void IIC_Start(void)
{
    IIC_SDA(0);     // 当SCL为高时,SDA从高变成低, 表示起始信号 
    iic_delay();
    IIC_SCL(0);     
    iic_delay();
}

在起始信号发出后,总线处于忙状态,由本次数据传输的主从设备独占,其他器件无法访问总线。

停止信号

void iic_stop(void)
{
    IIC_SDA(0);     // 当SCL为高时, SDA从低变成高, 表示停止信号 
    iic_delay();
    IIC_SCL(1);
    iic_delay();
    IIC_SDA(1);     // 发送I2C总线结束信号
    iic_delay();
}

在停止信号产生后,本次数据传输的主从设备释放总线,总线处于空闲状态。

应答信号

每当主机向从机发送完一个字节的数据后,主机总是需要等待从机给出一个应答信号,以确认从机是否接收到了数据。主机SCL拉高(大于4us),读取从机SDA的电平,如果为低电平,则产生应答。

  • 应答信号为低电平时,规定为有效应答为(ACK),表示接收器件已经成功接收到了这个字节。
  • 若应答信号为高电平,则是非应答位,表示失败接收。
/* 等待应答信号到来,返回值为1表示接收应答失败,返回值为0表示接收应答成功 */
uint8_t iic_wait_ack(void)
{
    uint8_t waittime = 0;
    uint8_t rack = 0;
    IIC_SDA(1);     // 主机释放SDA线 
    iic_delay();
    IIC_SCL(1);     // 从机可以返回ACK 
    iic_delay();
    while (IIC_READ_SDA)    // 等待应答 
    {
        waittime++;
        if (waittime > 250)
        {
            iic_stop();
            rack = 1;
            break;
        }
    }
    IIC_SCL(0);     // SCL=0, 结束ACK检查
    iic_delay();
    return rack;
}

/* 产生ACK应答 */
void iic_ack(void)
{
    IIC_SDA(0);     // SDA = 0,表示应答 
    iic_delay();
    IIC_SCL(1);     // 产生一个时钟 
    iic_delay();
    IIC_SCL(0);
    iic_delay();
    IIC_SDA(1);     // 主机释放SDA线 
    iic_delay();
}

/* 产生ACK应答 */
void iic_nack(void)
{
    IIC_SDA(1);     // SDA = 1,表示不应答 
    iic_delay();
    IIC_SCL(1);     // 产生一个时钟 
    iic_delay();
    IIC_SCL(0);
    iic_delay();
}

数据传输

IIC信号在数据传输过程中,当SCL为高电平时,SDA必须保持稳定状态,不允许有电平跳变,只有当SCL为低电平时,数据线才允许高低电平变化。数据传输图。输出到SDA上的字节必须是8位,数据传输时先传最高位(MSB),每个被传输的字节后面必须跟着一位应答位,也就是说,一帧有9位。当一个字节按数据位从高位到低位的顺序传输完,紧接着从设备拉低SDA线,回传给主设备一个应答位ACK,此时才认为一帧数据才被传输完成。如果一段时间内未收到从机的应答信号,则自动认为从机已经正确接收到了数据。每一帧数据共有9bit。如果是设备地址数据,则包含7bit设备地址+1bit读写位+1位应答位。如果是发送数据,则包含8bit数据+1bit应答位。多数从设备的地址位7位或者10位。8位设备地址=7位从机地址+读/写地址。地址帧中的第8位为读/写位。0表示写数据。1表示读数据。向7位地址设备写数据。向7位地址设备读数据。向10位地址设备写数据。向10位地址设备读数据。

/* IIC发送一个字节 data: 要发送的数据 */
void iic_send_byte(uint8_t data)
{
    uint8_t t;
    for (t = 0; t < 8; t++)
    {
        IIC_SDA((data & 0x80) >> 7); // 高位先发送 
        iic_delay();
        IIC_SCL(1);
        iic_delay();
        IIC_SCL(0);
        data <<= 1; // 左移1位,用于下一次发送 
    }
    IIC_SDA(1);   //发送完成, 主机释放SDA线 
}

/* IC读取一个字节 ack:  ack=1时,发送ack; ack=0时,发送nack 返回值:接收到的数据 */
uint8_t iic_read_byte(uint8_t ack)
{
    uint8_t i, receive = 0;
    for (i = 0; i < 8; i++ )    // 接收1个字节数据
    {
        receive <<= 1;  // 高位先输出,所以先收到的数据位要左移 
        IIC_SCL(1);
        iic_delay();
        if (IIC_READ_SDA)
        {
            receive++;
        }
        
        IIC_SCL(0);
        iic_delay();
    }
    if (!ack)
    {
        iic_nack();     // 发送nACK 
    }
    else
    {
        iic_ack();      // 发送ACK 
    }
    return receive;
}
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号