I2C通信协议基础笔记

本文详细介绍了I2C通信协议的工作原理,包括启动条件、停止条件、寻址、读写位、数据帧和应答信号。通过C语言展示了如何模拟I2C信号,包括开始信号、寻址、数据传输和停止位的实现。此外,还总结了I2C协议的优缺点,如两线通信、多主多从支持以及简单的硬件需求。
摘要由CSDN通过智能技术生成

I2C通信简介

I2C使用两根线,一个SDA串行数据线和一根SCL时钟线,半双工,支持一主多从或者多主多从模式
SDA:主机和从机发送和接收数据的线路
SCL:传输时钟信号的线路

I2C工作原理

I2C协议

启动条件:在SCL线从高电平切换到低电平之前 ,SDA线从高电平 切换到低电平。

停止条件: SCL 线由低电平切换到高电平后 ,SDA 线由低电平 切换到高电平。

地址帧: 每个从机唯一的 7 或 10 位序列,当主机想要与它通信时,它会识别从机。

读/写位: 指定主机是向从机发送数据(低电压电平)还是向从机请求数据(高电压电平)的单个位。

ACK/NACK 位: 消息中的每一帧后跟一个确认/不确认位。如果成功接收到地址帧或数据帧,则接收设备会向发送方返回一个 ACK​​ 位。

寻址

I2C 没有像 SPI 这样的从机选择线,因此它需要另一种方式让从机知道数据正在发送给它,而不是另一个从机。它通过 寻址来做到这一点。地址帧始终是新消息中起始位之后的第一个帧。

主机将要与之通信的从机的地址发送给与其连接的每个从机。然后,每个从机将从主机发送的地址与其自己的地址进行比较。如果地址匹配,它会向主机发送一个低电压 ACK 位。如果地址不匹配,从机什么也不做,SDA 线保持高电平。

读写位

地址帧末尾包含一个位,用于通知从机主机是要向其写入数据还是要从其接收数据。如果主机要向从机发送数据,读/写位为低电压电平。如果主机向从机请求数据,则该位为高电平。

数据帧

主机检测到从机的 ACK 位后,第一个数据帧就可以发送了。

数据帧总是 8 位长,并以最高有效位在前发送。每个数据帧后面紧跟一个 ACK​​/NACK 位,以验证该帧是否已成功接收。ACK 位必须由主机或从机(取决于谁在发送数据)接收到,然后才能发送下一个数据帧。

发送完所有数据帧后,主机可以向从机发送停止条件以停止传输。停止条件是在 SCL 线上从低到高转换之后 SDA 线上的电压从低到高转换,而 SCL 线保持高电平。

I2C数据传输步骤

下文利用C语言展示如何通过GPIO引脚模拟I2C信号,同时通过示波器信号加深印象

1. 开始信号

主机通过将 SDA 线从高电压电平切换到低电压电平 ,然后 将 SCL 线从高电平切换到低电平,向每个连接的从机发送启动条件

 void IIC_Start(void)
{
    
	SDA_OUT();     	//设置SDA线为输出
	SCL_OUT();     	//设置SCL线为输出
	SET_IIC_SDA=1;	//SDA置高  
	SET_IIC_SCL=1;  //SCL置高
	delay_us(4);    //让数据保持一段时间
	
    //SCL线从高电平切换到低电平之前 ,SDA线从高电平  切换到低电平
 	IIC_SDA=0;		
	delay_us(4);    
	IIC_SCL=0;		//钳住I2C总线,准备发送或接收数据 
}

起始信号

2.寻址

主机向每个从机发送它想与之通信的从机的 7 位或 10 位地址,以及读/写位

//发送七位地址数据+一位读写位
void gpio_iic_write(int data)
{
    int i = 0;
    for (i = 0; i < 8; i++)
    {
        if (data & (1 << (7 - i)))
        {
            SET_IIC_SDA(1);
        }
        else
        {
            SET_IIC_SDA(0);
        }
        delay(1);
        SET_IIC_SCL(1);
        delay(2);
        SET_IIC_SCL(0);
        delay(1);
    }
}
//从机地址要左移一位,加上一位读写位
gpio_iic_write((SlaveAddr << 1) | I2C_TX);

寻址

3. 主机等待返回应答信号

每个从机将主机发送的地址与自己的地址进行比较。如果地址匹配,从机通过将 SDA 线拉低一位来返回一个 ACK​​ 位。如果来自主机的地址与从机自己的地址不匹配,则从机将 SDA 线保持为高电平。

//主机发送数据,此时从机每次接收到一帧数据之后,要返回一个低电平,那么主机就要接收这个ack,因此主机数据线引脚要设置为输入
void gpio_iic_slave_ack(void)
{
    SDA_IN();
    delay(1);
    SET_IIC_SCL(1);
    delay(1);
    GET_IIC_SDA();
    SET_IIC_SCL(0);
    osa_udelay(1);
    SDA_OUT(1);//接收到ack之后,要马上设置回输出引脚,继续发送信号
    delay(1);
}

应答

4. 数据帧

主机发送或者接收数据帧

//读取一个字节数据
int gpio_iic_read(void)
{
    int data = 0;
    int i = 0;
    volatile int temp = 0;

    SET_SDA_IN();
    for (i = 0; i < 8; i++)
    {
        delay(1);
        SET_IIC_SCL(0);
        delay(2);
        SET_IIC_SCL(1);
        delay(1);
      
        temp = GET_IIC_SDA();//读取sda一个bit有效数据,而且是从高位往低位接收数据,所以需要移位处理
        if (temp)
        {
            data |= (1 << (7 - i)); // MSB
        }
    }
    delay(1);
    SET_IIC_SCL(0);
    delay(1);
    return data;
}
//发送八位数据
void gpio_iic_write(int data)
{
    int i = 0;
    for (i = 0; i < 8; i++)
    {
        if (data& (1 << (7 - i)))
        {
            SET_IIC_SDA(1);
        }
        else
        {
            SET_IIC_SDA(0);
        }
        delay(1);
        SET_IIC_SCL(1);
        delay(2);
        SET_IIC_SCL(0);
        delay(1);
    }
}
//最好这样传参
gpio_iic_write(data & 0xff);//除了后面八位有效数据其他均抹去

5.应答信号

传输完每个数据帧后,接收设备会向发送方返回另一个 ACK​​ 位,以确认已成功接收到该帧

同3

6.停止位

要停止数据传输,主机在将 SDA 变为高之前通过将 SCL 变为高来向从机发送停止条件
或者说,在SCL变为高之后,将SDA变为高,停止条件成立
有时候同样的文字的描述也会让人感到疑惑,结合看图会更好理解

void gpio_iic_stop(void)
{
    SDA_OUT();
    SET_IIC_SDA(0);
    delay(2);
    SET_IIC_SCL(1);
    delay(4);
    SET_IIC_SDA(1);
    delay(2);
}

在这里插入图片描述

总结I2C优缺点

优点

  1. 只用两根线
  2. 支持多主多从
  3. ACK/NACK 位确认每帧传输成功
  4. 硬件不如 UART 复杂
  5. 众所周知且广泛使用的协议

缺点

  1. 数据传输速率比 SPI 慢
  2. 数据帧的大小限制为 8 位
  3. 需要实现比 SPI 更复杂的硬件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值