0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何更加深入理解I2C总线、协议及应用

黄工的嵌入式技术圈 来源:黄工的嵌入式技术圈 2020-03-20 09:29 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

开始和停止条件

SCL时钟电平为高:

SDA数据线由高 -> 低 为总线开始条件;

SDA数据线由低 -> 高 为总线结束条件;

(注意:开始之后将SCL变为低电平,防止误操作SDA使其通信停止,见源代码)

时序图:

源代码程序:

/************************************************

函数名称 : I2C_Start

功 能 : I2C开始

参 数 : 无

返 回 值 : 无

作 者 : strongerHuang

*************************************************/

voidI2C_Start(void)

{

I2C_SCL_HIGH; //SCL高

I2C_Delay();

I2C_SDA_HIGH; //SDA高 -> 低

I2C_Delay();

I2C_SDA_LOW; //SDA低

I2C_Delay();

I2C_SCL_LOW; //SCL低(待写地址/数据)

I2C_Delay();

}

/************************************************

函数名称 : I2C_Stop

功 能 : I2C停止

参 数 : 无

返 回 值 : 无

作 者 : strongerHuang

*************************************************/

void I2C_Stop(void)

{

I2C_SDA_LOW; //SDA低 -> 高

I2C_Delay();

I2C_SCL_HIGH; //SCL高

I2C_Delay();

I2C_SDA_HIGH; //SDA高

I2C_Delay();

}

数据位传输

SCL时钟电平为低, 可以改换SDA数据线的电平,在SCL上升沿的过程将SDA数据发送出去。

(切记:请先将SCL变为低电平,再改变SDA电平状态。 主要用于I2C读写Byte函数,这两个函数网上很多人写的不规范,引用需注意,在下面我会举例说明)

时序图:

发送一位“高”数据流程:

SCL_LOW时钟低 -> SDA_HIGH数据 -> SCL_HIGH时钟高

应答位信息

I2C是以字节(8位)的方式进行传输,总线上每传输完1字节之后会有一个应答信号,主器件(主机)需要产生对应的一个额外时钟。

应答位产生及接收:

1.在(主机)写数据的时候是从机应答(给主机),主机检测;

2.在(主机)读数据的时候是主机应答(给从机),从机检测;

(我们借助I2C读写函数一起理解)

1.主机写,从机应答,主机读取应答

时序图:

源代码:

/************************************************

函数名称 : I2C_GetAck

功 能 : I2C主机读取应答(或非应答)位

参 数 : 无

返 回 值 : I2C_ACK ----- 应答

I2C_NOACK --- 非应答

作 者 : strongerHuang

*************************************************/

uint8_t I2C_GetAck(void)

{

uint8_t ack;

I2C_SCL_LOW; //SCL低 -> 高

I2C_Delay();

I2C_SDA_HIGH; //释放SDA(开漏模式有效)

I2C_Delay();

I2C_SCL_HIGH; //SCL高(读取应答位)

I2C_Delay();

if(I2C_SDA_READ)

ack = I2C_NOACK;//非应答

else

ack = I2C_ACK; //应答

I2C_SCL_LOW; //SCL低

I2C_Delay();

returnack;

}

2.主机读,主机产生应答

时序图:

源代码:

/************************************************

函数名称 : I2C_PutAck

功 能 : I2C主机产生应答(或非应答)位

参 数 : I2C_ACK ----- 应答

I2C_NOACK --- 非应答

返 回 值 : 无

作 者 : strongerHuang

*************************************************/

voidI2C_PutAck(uint8_t Ack)

{

I2C_SCL_LOW; //SCL低

I2C_Delay();

if(I2C_ACK == Ack)

I2C_SDA_LOW; //应答

else

I2C_SDA_HIGH; //非应答

I2C_Delay();

I2C_SCL_HIGH; //SCL高 -> 低

I2C_Delay();

I2C_SCL_LOW; //SCL低

I2C_Delay();

}

I2C写一字节

这里说的I2C写,是主机往从机接入1Byte的数据;

“写”要求按照上面的“数据为传输”来操作:在SCL时钟为低电平时准备好,待SCL为高电平时发送出去。

写完一字节(8位)之后,读取从机的应答位:

若为0,表示从机应答,可以继续下一步操作;

若为1,表示从机非应答,不能进行下一步操作。

注意:

I2C写一字节,不是EEPROM写一字节(需要区分开来)

写一字节时序(前面8位数据 + 最后1为应答):

源代码:

/************************************************

函数名称 : I2C_WriteByte

功 能 : I2C写一字节

参 数 : Data --- 数据

返 回 值 : 无

作 者 : strongerHuang

*************************************************/

void I2C_WriteByte(uint8_t Data)

{

uint8_t cnt;

for(cnt=0; cnt<8; cnt++)

{

I2C_SCL_LOW; //SCL低(SCL为低电平时变化SDA有效)

I2C_Delay();

if(Data & 0x80)

I2C_SDA_HIGH;//SDA高

else

I2C_SDA_LOW; //SDA低

Data <<= 1;

I2C_Delay();

I2C_SCL_HIGH; //SCL高(发送数据)

I2C_Delay();

}

I2C_SCL_LOW; //SCL低(等待应答信号)

I2C_Delay();

I2C_GetAck(); //读取应答位

}

提示:

网上常见几种关于“I2C写数据函数”的不规范写法, 或许整个I2C驱动能通信成功,但各个函数之间依赖关系很强,不便理解,也不是标准的函数。

1.首先将SCL置高:

voidI2C_WriteByte(uint8_t Data)

{

uint8_t cnt;

for(cnt=0; cnt<8; cnt++)

{

I2C_SCL_HIGH;

if(Data & 0x80)

I2C_SDA_HIGH;

else

I2C_SDA_LOW;

Data <<= 1;

I2C_SCL_LOW;

}

I2C_GetAck();

}

这种程序的写法有一个致命的地方(有可能停止,或重新开始I2C通信):

首先将SCL置高:

A.若之前SDA是低电平,第一位写入高电平,将停止I2C通信。

B.若之前SDA是高电平,第一位写入低电平,将重新开始I2C通信。

2.写完8位数据之后,未将SCL置低(也就是SCL保持高电平状态)

由于写完8位数据之后,将要读取应答信号,也就是要SDA将从输出状态变为输入状态。

这个时候SCL为高,如果SDA最后一位是低且SDA是开漏模式,需要将SDA释放,也就是要将SDA置位高,那么,这个时候就进行了一个停止操作。

3.时序混乱

void I2C_WriteByte(uint8_t Data)

{

uint8_t cnt;

I2C_SCL_HIGH;

for(cnt=0; cnt<8; cnt++)

{

if(Data & 0x80)

I2C_SDA_HIGH;

else

I2C_SDA_LOW;

Data <<= 1;

I2C_SCL_LOW;

I2C_SCL_HIGH;

}

I2C_GetAck();

}

多种问题的例子,有可能产生以下问题:

A.有可能多写1位数据;

B.有可能停止I2C通信;

C.有可能重新开始I2C通信。

I2C读一字节

I2C的读一字节函数,其实和“写一字节”类似,只是数据传输方向相反,应答的方向也是相反。

读完一字节(8位)之后,由主机产生应答(或非应答)位:

若产生应答,表示可以继续读下一字节操作(从设备地址指向下一字节);

若产生非应答,表示不可以继续读下一字节操作;

网上I2C读数据程序和“写数据”类似,存在很多不标准的版本,参考时请注意。

读一字节时序(主机读取前面8位数据 + 主机产生1为非应答<连续读,主机产生应答位>):

源代码:

/************************************************

函数名称 : I2C_ReadByte

功 能 : I2C读一字节

参 数 : ack --------- 产生应答(或者非应答)位

返 回 值 : data -------- 读取的一字节数据

作 者 : strongerHuang

*************************************************/

uint8_t I2C_ReadByte(uint8_t ack)

{

uint8_t cnt;

uint8_t data;

I2C_SCL_LOW; //SCL低

I2C_Delay();

I2C_SDA_HIGH; //释放SDA(开漏模式有效)

for(cnt=0; cnt<8; cnt++)

{

I2C_SCL_HIGH; //SCL高(读取数据)

I2C_Delay();

data <<= 1;

if(I2C_SDA_READ)

data |= 0x01; //SDA为高(数据有效)

I2C_SCL_LOW; //SCL低

I2C_Delay();

}

I2C_PutAck(ack); //产生应答(或者非应答)位

return data; //返回数据

}

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 协议
    +关注

    关注

    2

    文章

    620

    浏览量

    41192
  • I2C
    I2C
    +关注

    关注

    28

    文章

    1562

    浏览量

    131743
  • SCL
    SCL
    +关注

    关注

    1

    文章

    244

    浏览量

    18071
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    SGM4541 I2C总线过压保护器:设计与应用的详细解析

    工程师们在设计I2C总线系统时提供了可靠的过压保护解决方案。今天,我们就来深入剖析这款保护器的关键特性、应用场景以及各项参数。 文件下载: SGM4541.pdf 一、产品概述 SGM4541是一款低静态
    的头像 发表于 03-17 16:30 389次阅读

    SGM4541A:I2C总线过压保护的理想之选

    SGM4541A:I2C总线过压保护的理想之选 在电子设备的设计中,I2C总线的稳定运行至关重要。而SGM4541A作为一款低IQ I2C
    的头像 发表于 03-17 16:30 215次阅读

    PCA9545A/45B/45C:4通道I2C总线开关的深度解析

    PCA9545A/45B/45C:4通道I2C总线开关的深度解析 在电子工程师的日常设计工作中,I2C总线开关是实现多设备通信和信号切换的重
    的头像 发表于 02-10 11:50 1004次阅读

    I2C总线-通信线缆长度的影响及改进措施

    是差分信号传输,也就克服了I2C总线的 线缆长度限制了。当然价格也是比较贵的,一对芯片要将近30元。 (4)通信 频率,这个很好理解,在各种通信中,有一个共同的规律,通信速率与误码率成正比,通信频率越低,误码率也越低,所以我们
    发表于 01-21 06:03

    探索PCF8584:I2C总线控制器的卓越之选

    探索PCF8584:I2C总线控制器的卓越之选 在电子工程师的日常工作中,选择合适的芯片来实现特定功能至关重要。今天,我们就来深入探讨一款功能强大的I2C
    的头像 发表于 12-28 15:40 756次阅读

    P82B715:I2C总线扩展的得力助手

    P82B715:I2C总线扩展的得力助手 在电子设计领域,I2C总线是一种常用的通信协议,但它的总线
    的头像 发表于 12-26 10:20 1548次阅读

    基于FPGA的I2C控制模块设计

    I2C_WRITE_WDATA.v模块实现I2C写时序,I2C_Controller (I2C控制器)例化了I2C_WRITE_WDATA.
    的头像 发表于 12-26 09:48 5976次阅读
    基于FPGA的<b class='flag-5'>I2C</b>控制模块设计

    基于FPGA的I2C通信协议设计

    I2C(Inter-Integrated Circuit)是一种由飞利浦半导体(现为恩智浦半导体)在1980年代初开发的同步、串行、半双工的总线型通信协议。主要用于近距离(同一块印刷电路板(PCB
    的头像 发表于 12-26 09:44 6357次阅读
    基于FPGA的<b class='flag-5'>I2C</b>通信<b class='flag-5'>协议</b>设计

    深入解析 TCA9539:低电压 16 位 I2C 和 SMBus I/O 扩展器

    深入解析 TCA9539:低电压 16 位 I2C 和 SMBus I/O 扩展器 在电子设计的广阔领域中,I/O 扩展器是一款关键的小工具。它能够为系统提供更多的输入输出接口,让设计
    的头像 发表于 12-25 09:30 552次阅读

    深入解析TCA9617B:I2C总线中继器的卓越之选

    深入解析TCA9617B:I2C总线中继器的卓越之选 在电子工程师的日常设计工作中,I2C总线和SMBus系统的应用极为广泛。而TCA961
    的头像 发表于 12-22 15:20 638次阅读

    AS32X601的I2C模块操作EEPROM详解

    I2C接口模块实现了I2C协议的标准模式和快速模式,支持多主机I2C总线架构。其标准模式为100K,快速模式400K。而EEPROM,作
    的头像 发表于 12-21 21:39 1588次阅读
    AS32X601的<b class='flag-5'>I2C</b>模块操作EEPROM详解

    I2C总线协议

    I2C 总线使用两根信号线(数据线 SDA 和时钟线 SCL)在设备间传输数据。SCL 为单向时钟线,固定由主机驱动。SDA 为双向数据线,在数据传输过程中由收发两端分时驱动。 I2C 总线
    发表于 12-15 08:07

    I2C的缺点介绍

    影响信号完整性并导致通信错误。上拉电阻值的计算取决于总线电容、所需上升时间和电源电压等因素。 寻址限制: I2C 协议支持有限数量的唯一地址,通常为 7 或 10 位长,这限制了可连接到单个
    发表于 11-27 06:10

    深入剖析I2C协议

    I2C是由Philips开发的简单的双向两线总线,在深入浅出理解SPI协议中,我们区分了单工,半双工,全双工
    的头像 发表于 08-21 15:10 3884次阅读
    <b class='flag-5'>深入</b>剖析<b class='flag-5'>I2C</b><b class='flag-5'>协议</b>

    I2C总线通信,为什么要进行电气隔离?

    I2C总线采用双向二线制,支持多主机多从机通信,具备高可靠性、抗干扰能力强,广泛应用于嵌入式系统中。
    的头像 发表于 08-11 11:04 2670次阅读
    <b class='flag-5'>I2C</b><b class='flag-5'>总线</b>通信,为什么要进行电气隔离?