STM32 —— IIC 协议入门

STM32 —— IIC 协议入门

简介

IIC 也称 I²C,是一个多主从的串行总线,属于两线式串行总线,由飞利浦公司开发的用于微控制器( MCU )和外围设备(从设备)进行通信的一种总线,属于半双工同步传输类总线,一主多从(一个主设备(Master),多个从设备(Slave))的总线结构,总线上的每个设备都有一个特定的设备地址,以区分同一 IIC 总线上的其他设备,仅由两条线就能完成多机通讯,一条 SCL 时钟线,另外一条双向数据线 SDA ,IIC 总线要求每个设备 SCL / SDA 线都是漏极开路模式,因此必须带上拉电阻才能正常工作。I²C 协议占用引脚少,硬件实现简单,可扩展性强,I²C 数据传输速率有标准模式(100kbps)、快速模式(400kbps)和高速模式(3.4Mbps)

IIC 通信与 UART,还有 SPI 统称为串行接口通信,不过它们之间还是有区别的,如UART的负电平逻辑,还有 UART 通信不需要时钟,只需要特定的波特率即可,SPI 与 IIC 都可以有一个主机,多个从机的情况,不过 IIC 适用于短距离传输,如片间通信,摄像头的配置等场景

物理 IIC 接口有两根双向线,串行时钟线( SCL )和串行数据线( SDA )组成,可用于发送和接收数据,但是通信都是由主设备发起,从设备被动响应,实现数据的传输

时序

一个控制器里面可以含有多个 IIC 控制器,一个 IIC 控制器可以挂载多个 IIC 设备,这些 IIC 设备都通过 SDA,SCL 和主机进行通信。

IDLE:

表示总线空闲状态。此状态下时钟信号 SCL 和数据信号 SDL 均为高电 平,此时无 IIC 设备工作

START:

表示起始状态。在 IDLE 状态下,时钟信号 SCL 继续保持高电平,数据信号 SDL 出现由高电平转换为低电平的下降沿,此时产生一个起始信号,与总线相连的I2C设备检测到起始信号之后,进入起始状态等待控制字节的输入

Read or Write:

表示 IIC 设备读写状态

STOP:

表示停止状态。完成数据读写后,SCL 保持高电平,SDL 产生一个由低电平转换为高电平的上升沿信号之后,产生停止信号,总线回到空闲状态

读写时序状态如下:

SCL 为低电平期间,SDA 允许数据变换(1 代表高电平,0 代表低电平)。SCL 为高电平期间,SDA 数据必须保持稳定,因此一个时钟周期传输 1bit 数据,每次传输 8 个 bit 即一个字节,主机将在最后一个数据时钟末释放 SDA 总线使从机应答,在传输完 1 字节数据后的第一个时钟周期 SCL 为高电平,如果 SDA 未被检测到低电平,则视为非应答,代表此次数据传输失败

注意:数据传输是以高位在前,低位在后

传输数据

通信过程

主设备与从设备的一般通信过程

主设备给从设备发送/写入数据

  1. 主设备发送一个开始( START )信号

  2. 发出一个设备地址(用来确定是往哪一个芯片写数据)到从设备,方向(读/写,0 表示写,1 表示读)

  3. 等待从设备响应( ACK ),从设备回应(用来确定这个设备是否存在),然后就可以传输数据

  4. 主设备发送一个字节数据给从设备,并等待回应

  5. 每传输一字节数据,接收方要有一个回应信号(ACK 确定数据是否接受完成),然后再传输下一个数据

  6. 数据发送完之后,主设备就会发送一个停止( STOP )信号

主设备从从设备接收/读取数据

  1. 主设备发送一个开始( START )信号

  2. 发出一个设备地址(用来确定是往哪一个芯片写数据)到从设备,方向(读/写,0 表示写,1 表示读)

  3. 等待从设备响应( ACK )从设备回应(用来确定这个设备是否存在),然后就可以传输数据

  4. 主设备发送一个字节数据给从设备,并等待回应

  5. 每传输一字节数据,接收方要有一个回应信号(ACK 确定数据是否接受完成),然后再传输下一个数据。

  6. 数据发送完之后,一般接收到最后一个数据后会发送一个无效响应( NACK ),主设备就会发送一个停止( STOP )信号。

产生开始信号和停止信号

完整数据发送周期图如下:

开始信号:在 SCL 线为高电平时,SDA 线由高电平变为低电平

结束信号:在 SCL 线为高电平时,SDA 线由低电平变为高电平

将数据发送出去

在 SCL 为高电平时,会将 SDA 上的电平信号传输出去,当 SCL 为低电平时可以改变 SDA 上的电平信号

注意:在传输数据的过程中 SCL 必须保持高电平。第一个发送的数据必须是从设备地址,只有找到从设备地址才可以开始发送下面的信息

IIC 页写与单字节写

IIC 单字节写与页写的最大的区别:单字节写按照 IIC 协议每次写入一个字节,产生一个 stop 信号,页写可以允许写入多个字节数据,但不能超过设备单页包含的最大存储数,写入多个字节后,最终主机发送一个 stop 信号

通信的实现

使用 IIC 控制器实现(硬件 IIC )

就是使用芯片上的 IIC 外设,也就是硬件 IIC ,它有相应的 IIC 驱动电路,有专用的 IIC 引脚,效率更高,写代码会相对简单,只要调用 IIC 的控制函数即可,不需要用代码去控制 SCL、SDA 的各种高低电平变化来实现 IIC 协议,只需要将 IIC 协议中的可变部分(如:从设备地址、传输数据等等)通过函数传参给控制器,控制器自动按照I2C协议实现传输,但是如果出现问题,就只能通过示波器看波形找问题

使用 GPIO 通过软件模拟实现(软件 IIC )

软件模拟 IIC 比较重要,因为软件模拟的整个流程比较清晰,哪里出来 bug,很快能找到问题,模拟一遍会对 IIC 通信协议更加熟悉,这就是我们常说的软件 IIC

如果芯片上没有 IIC 控制器,或者控制接口不够用了,通过使用任意 I/O 口去模拟实现 IIC 通信协议,手动写代码去控制 I/O 口的电平变化,模拟IIC协议的时序,实现 IIC 的信号和数据传输

通信协议

IIC 总线协议无非就是几样东西:起始信号、停止信号、应答信号、以及数据有效性

空闲状态

时钟线( SCL )和数据线( SDA )接上拉电阻,默认高电平,表示总线是空闲状态

从设备地址

从设备地址用来区分总线上不同的从设备,一般发送从设备地址的时候会在最低位加上读/写信号,比如设备地址为 0x50,0 表示读,1 表示写,则读数据就会发送 0x50,写数据就会发送 0x51

起始( START )信号

IIC 通信的起始信号由主设备发起,SCL 保持高电平,SDA 由高电平跳变到低电平

// 起始信号
void IIC_start(void)
{
    // 1.首先把数据线设置为输出模式
    // 总线空闲, SCL和SDA输出高
    SCL = 1;
    SDA = 1;
    delay_us(5);
	
    // SDA由高变低
    SDA = 0;
    delay_us(5);
	
    // 拉低SCL开始传输数据
    SCL = 0;
}

停止( STOP )信号

IIC 通信的停止信号由主设备终止,SCL 保持高电平,SDA由低电平跳变到高电平

// 停止信号
void IIC_stop(void)
{
    // 1.首先把数据线设置为输出模式
	
    // 拉高时钟线
    SDA = 0;
    delay_us(5);
    SCL = 1;
    delay_us(5);
	
    // SDA由低变高
    SDA = 1;
}

数据有效性

IIC 总线进行数据传送时,在 SCL 的每个时钟脉冲期间传输一个数据位,时钟信号 SCL 为高电平期间,数据线 SDA 上的数据必须保持稳定,只有在时钟线 SCL 上的信号为低电平期间,数据线 SDA 上的高电平或低电平状态才允许变化,因为当 SCL 是高电平时,数据线 SDA 的变化被规定为控制命令( START 或 STOP ,也就是前面的起始信号和停止信号)

应答信号( ACK:有效应答,NACK:无效应答 )

接收端收到有效数据后向对方响应的信号,发送端每发送一个字节( 8 位)数据,在第 9 个时钟周期释放数据线去接收对方的应答

当 SDA 是低电平为有效应答( ACK ),表示对方接收成功

当 SDA 是高电平为无效应答( NACK ),表示对方没有接收成功

发送数据需要等待接收方的应答:

// 等待ACK   1-无效    0-有效
u8 IIC_wait_ack(void)
{
    u8 ack = 0;
	
    // 数据线设置为输入
	
    // 拉高时钟线
    SCL = 1;
    delay_us(5);
    // 获取数据线的电平
    if(SDA)
    {   // 无效应答
        ack = 1;
        IIC_stop();
    }
    else
    {   // 有效应答
        ack = 0;
        // 拉低SCL开始传输数据
        SCL = 0;
        delay_us(5);
    }
	
    return ack;
}

接收数据需要向发送方发送应答:

void IIC_ack(u8 ack)
{
    // 数据线设置为输出
	
    SCL = 0;
    delay_us(5);
	
    if(ack)
        SDA = 1; // 无效应答
    else
        SDA = 0; // 有效应答
    delay_us(5);
    SCL = 1;
    // 保持数据稳定
    delay_us(5);
    // 拉低SCL开始传输数据
    SCL = 0;
}

参考资料

  1. IIC协议简介

  2. IIC协议解析

  3. IIC通信协议,搞懂这篇就够了

posted @ 2022-11-17 16:26  ppqppl  阅读(345)  评论(0编辑  收藏  举报