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

    文章

    570

    浏览量

    38909
  • I2C
    I2C
    +关注

    关注

    28

    文章

    1346

    浏览量

    120814
  • SCL
    SCL
    +关注

    关注

    1

    文章

    238

    浏览量

    16866
收藏 人收藏

    评论

    相关推荐

    最简单的总线通讯!I2C通讯总线的原理原来这么好懂

    通讯I2C
    安泰仪器维修
    发布于 :2024年01月02日 11:16:31

    I2C总线的使用与编程

    I2C总线是飞利浦公司在20世纪80年代初由S定义的一种二线制总线系统。I2C总线是一种双向的,专为简单但高效的控制应用而设计。 它广泛应用
    发表于 09-04 07:23

    全面掌握面试必考题I2C协议 - 第13节

    I2C协议
    充八万
    发布于 :2023年09月01日 19:08:34

    全面掌握面试必考题I2C协议 - 第12节

    I2C协议
    充八万
    发布于 :2023年09月01日 19:07:43

    全面掌握面试必考题I2C协议 - 第11节

    I2C协议
    充八万
    发布于 :2023年09月01日 19:06:53

    全面掌握面试必考题I2C协议 - 第10节

    I2C协议
    充八万
    发布于 :2023年09月01日 19:06:03

    全面掌握面试必考题I2C协议 - 第7节

    I2C协议
    充八万
    发布于 :2023年09月01日 19:03:32

    全面掌握面试必考题I2C协议 - 第6节

    I2C协议
    充八万
    发布于 :2023年09月01日 19:02:42

    全面掌握面试必考题I2C协议 - 第5节

    I2C协议
    充八万
    发布于 :2023年09月01日 19:01:51

    全面掌握面试必考题I2C协议 - 第4节

    I2C协议
    充八万
    发布于 :2023年09月01日 19:01:01

    全面掌握面试必考题I2C协议 - 第2节 #硬声创作季

    I2C协议
    充八万
    发布于 :2023年09月01日 18:59:21

    全面掌握面试必考题I2C协议 - 第1节

    I2C协议
    充八万
    发布于 :2023年09月01日 18:58:30

    80 第23.1讲 I2C实验-I2C协议和6U的I2C控制器详解 - 第2

    程序代码I2C协议
    充八万
    发布于 :2023年08月17日 10:03:33

    基于 FPGA 的模拟 I2C协议系统设计

    的话讲 I2C 总线的硬件设计工作就是连接 SDA 和 SCL 两条线,依靠 I2C 协议完成软件工作。在 I2C
    发表于 08-14 18:21

    深入理解总线协议

    目前常用的微机与外设之间进行数据传输的串行总线主要有I2C总线、SPI总线和SCI总线。其中I2C
    的头像 发表于 06-15 00:46 5999次阅读
    <b class='flag-5'>深入理解</b>单<b class='flag-5'>总线</b><b class='flag-5'>协议</b>