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

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

3天内不再提示

从IIC实测波形入手,去理解IIC的通信原理

FPGA之家 来源:CSDN技术社区 作者:码农爱学习 2021-04-09 18:07 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

单片机的朋友都知道IIC通信这个工具,但好多人只是会用,内部的原理不求甚解,或是想要了解其原理,但却对抽象的时序描述一头雾水。本文将从实测的IIC波形入手,带你看到真实的IIC样子,进而去理解IIC的通信原理。

1IIC基础知识

首先复习一下IIC基础知识,这部分看不懂的请先带着疑问,然后我们通过分析IIC的真实波形,这些疑问可能就豁然开朗了~

1.1 IIC是什么

IIC(Inter Integrated Circuit,集成电路总线)是一种由 PHILIPS 公司开发的两线式串行总线,用于连接微控制器及其外围设备。它是由数据线 SDA 和时钟 SCL 构成的串行总线,可发送和接收数据。在 CPU (单片机)与IIC模块之间、IIC模块与IIC模块之间进行双向传送。

IIC的一些特点:

IIC是半双工,而不是全双工

IIC是真正的多主机总线,(对比SPI在每次通信前都需要把主机定死,而IIC可以在通讯过程中,改变主机),如果两个或更多的主机同时请求总线,可以通过冲突检测和仲裁防止总线数据被破坏

起始和终止信号都是由主机发出的,连接到IIC总线上的器件,若具有IIC总线的硬件接口,则很容易检测到起始和终止信号

在起始信号后必须发送一个7位从机地址+1位方向位,用“0”表示主机发送数据,“1”表示主机接收数据。

每当主机向从机发送完一个字节的数据,主机总是需要等待从机给出一个应答信号,以确认从机是否成功接收到了数据

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

注:实际使用中,一般是单片机作为主机,其它器件作为从机,单片机先向器件发送信息表示要读取数据,之后转变传输方向,器件发送数据到单片机。

1.2 IIC物理连接

使用IIC通信的IIC器件有很多,比如陀螺仪加速度计MPU6050,EEPROM存储芯片AT24C02等,通过IIC总线,可以与单片机之间进行数据传输。

IIC通信线只有只有两根,数据线SDA的高低电平传输2进制的数据,时钟线SCL通过方波信号提供时钟节拍

多个IIC器件可以并联在IIC总线上,每个器件有特定的地址,分时共享IIC总线

实际使用IIC当然还要连接电源以及共地哦

4bc7726c-990f-11eb-8b86-12bb97331649.png

1.3 IIC时序

网上查找IIC的基础知识,可能会搜到这样的时序图:

4c0114a4-990f-11eb-8b86-12bb97331649.png

看起来好复杂的样子,这时可能一部分人就放弃思考了。

1.3.1 IIC起始结束信号

好吧,换个简单点的图,你也可能会搜到这样的图:

4c3b7a22-990f-11eb-8b86-12bb97331649.jpg

这张图看起来更简单一些,描述了IIC的起始和停止条件:

起始:时钟线SCL为高时,数据线SDA由高到低

停止:时钟线SCL为高时,数据线SDA由低到高

注:SDA和SCL同时为高时,为IIC总线的空闲状态

1.3.2 IIC应答

再来看下面这张图:

4c6a89c0-990f-11eb-8b86-12bb97331649.jpg

这表示IIC的应答机制

下面的波形:SCL,主机产生的时钟脉冲

上面的波形:SDA,主机发送的8位数据

中间的波形:SDA,从机在第9个时钟信号进行拉低回应,表示收到了主机发来的数据,拉高则表示不应答

注:实际上,上面和中间是同样的SDA线,这里只是分开示意。因为IIC应答是一种相互关系,单片机发数据给IIC器件,IIC器件要进行应答,表示收到了数据,同样,单片机接收IIC器件的数据后,也要给IIC器件一个应答。

既然发送完都需要对方回应,那什么时候使用不应答呢?就是在读取到本次数据后,如果不需要继续读取,则发送非应答,对方以为你没收到这次数据,则就不会继续发送了。

1.3.3 IIC完整传输时序

4fa7ff50-990f-11eb-8b86-12bb97331649.png

开始标志(S)发出后,主设备会传送一个7 位的Slave 地址,并且后面跟着一个第8位,称为Read/Write 位。

R/W 位表示主设备是在接受从设备的数据还是在向其写数据。

然后,主设备释放SDA 线,等待从设备的应答信号(ACK)。每个字节的传输都要跟随有一个应答位。

应答产生时,从设备将SDA 线拉低并且在SCL 为高电平时保持低。

数据传输以停止标志(P)结束,然后释放总线。但主设备也可以产生重复的开始信号去操作另一台从设备,而不发出结束标志。

所有的SDA 信号变化都要在SCL 时钟为低电平时进行,除了开始和结束标志

1.4 常用的数据收发方式(时序)

上面1.3小节是IIC的基础时序,在实际使用中,一般是对某个IIC器件的某个寄存器进行读写操作,因此,对于寄存器的读写操作,还要遵循下面的组合时序逻辑。

1.4.1 写一个字节

用于对IIC器件某个寄存器的配置,如对MPU6050的某些参数进行设置。

4fec4a0c-990f-11eb-8b86-12bb97331649.png

写寄存器时,主设备除了发出开始标志和地址位,还要加一个R/W 位,0 为写,1 为读

在第9 个时钟周期(高电平时),MPU6050 产生应答信号

主设备开始传送寄存器地址,并接到应答

然后开始传送寄存器数据,仍然要有应答信号

最后主设备发送停止信号。

1.4.2 连续写多个字节

对连续地址的写入,这个用的较少。

50364878-990f-11eb-8b86-12bb97331649.png

通信时序与上面的“写一个字节”类似,上面是写一个字节后就停止了,若要连续写,则继续写即可,只要可以收到从机Ack。

1.4.3 读一个字节

用于读取IIC器件某个寄存器的数值。

50705d9c-990f-11eb-8b86-12bb97331649.png

首先由主设备产生开始信号,然后发送从设备地址位和一个写数据位,等待应答

然后发送寄存器地址,才能开始读寄存器

收到应答信号后,主设备再发一个开始信号,然后发送从设备地址位和一个读数据位

然后,作为从设备的MPU6050 产生应答信号并开始发送寄存器中的数据

通信以主设备产生的拒绝应答信号(nACK)和结束标志(Stop)结束

拒绝应答信号(nACK)产生定义为SDA 数据在第9 个时钟周期一直为高

1.4.4 连续读多个字节

也是用于读取IIC器件某个寄存器的数值,当某些数据一位字节不够表示,或有一组连续的数据需要读时,可以使用该模式。

50a7c2f0-990f-11eb-8b86-12bb97331649.png

通信时序与上面的“读一个字节”类似,上面是读一个字节后就nAck叫停,若要连续写,则发送Ack,直到不需要继续读时再回复nAck。

复习了这么多,之前对IIC懵懵懂懂的是否依然犯迷糊,好了,现在从理论进入实践,看看真实的IIC是什么样子。

2初识IIC真实波形

下面这张图(请横屏观看)是通过示波器抓取的IIC波形,可以看到:

时钟线SCL是一种间歇性的方波(需要通信时才产生方波)

数据线SDA根据SCL提供的节拍,高电平代表数据1,低电平代表数据0

没有数据传输时,SDA和SCL均为高电平状态

起始信号后,数据是9个一组,包括8位的数据和另一方的1位回应

图中红色数字表示单片机发送的8位数据,黄色数字表示IIC器件回应的信号,低电平0表示器件收到了单片机发来的数据。

现在对IIC波形有没有多了一些直观的认识?下面再进入编程阶段,看看程序是怎么控制这两根线的。

3IIC软件编写逻辑

IIC通信可以使用单片机自带的硬件IIC,它提供了固定的引脚接口和函数库。也可以自己通过软件编写来实现IIC时序,这时就可以任选引脚,也方便其它硬件平台的移植。

下面通过软件IIC的编写,从软件角度理解IIC通信逻辑。

以下函数都是单片机在执行,即主机发出的动作,所以一定要从单片机的角度思考哦~

另外,不要看到程序就匆匆掠过,为帮助理解,我对代码进行了一定的注解,仔细分析每条代码,想想与IIC的逻辑如何对应起来,IIC逻辑还没懂的,读完本篇,分析过真实的IIC波形后,再来看看代码,会有不一样的体会。

起始IIC_Start()

//==================================//产生IIC起始信号//==================================void IIC_Start(void){ SDA_OUT(); //sda线输出 IIC_SDA=1; delay_us(2); IIC_SCL=1; //时钟线为高时 delay_us(2); IIC_SDA=0; //数据线由高到低 delay_us(4); IIC_SCL=0; //时钟线拉低,钳住IIC总线,准备发送数据}

最后一句SCL拉低,然后就准备产生时钟信号,发送数据了。

停止IIC_Stop()

//==================================//产生IIC停止信号//==================================void IIC_Stop(void){ SDA_OUT(); //sda线输出 IIC_SCL=0; //确保时钟线为低时,数据线才能变化为0,否则这就可能成起始信号了! delay_us(2); IIC_SDA=0; delay_us(2); IIC_SCL=1; //时钟线为高时 IIC_SDA=1; //数据线由低到高 delay_us(4); }

停止前也要确保SCL是拉低的状态。

最后SDA和SCL都为高,即释放IIC总线,IIC总线进入空闲状态。

等待应答IIC_wait_Ack()

//==================================//等待应答信号到来//用于发送模式下,发送8位后,等待器件应答第9位//返回值:1,接收应答失败// 0,接收应答成功//==================================u8 IIC_Wait_Ack(void){ u8 ucErrTime=0; SDA_IN(); //SDA设置为输入 IIC_SDA=1;delay_us(1); //SDA先拉高,若被从机拉低则说明收到应答信号 IIC_SCL=1;delay_us(1); //SCL拉高,产生第9位的脉冲 while(READ_SDA) { ucErrTime++; if(ucErrTime》250) { IIC_Stop(); return 1; } } IIC_SCL=0;//时钟输出0 //SCL拉低,结束第9位的脉冲 return 0; }

在一定是时间内检测SDA是否被从机拉低,被拉低则说明从机收到了数据。

产生应答IIC_Ack()

//==================================//产生ACK应答//用于读取模式(SDA为in)读了8位器件数据后,在第9位给出一个应答,我还要继续读//==================================void IIC_Ack(void){ IIC_SCL=0; //确保时钟线为低时,数据线才能变化为0,否则这就可能成起始信号了! SDA_OUT(); //SDA由读取改为发送 delay_us(2); IIC_SDA=0; //拉低SDA,表示应答 delay_us(2); IIC_SCL=1; //SCL先上升 delay_us(2); IIC_SCL=0; //SCL再下降,形成一个脉冲,应答才生效}

单片机在接收器件数据后,进行回应,表示接收到了器件的数据。

该函数用在连续读取多个字节时,每读完一个字节(8位),产生回应,表示还要进行读,这时器件就可以继续发数据了。

当单片机不需要继续读,如连续读的最后一个字节,或只读一个字节,单片机发送非应答信号,这时器件以为单片机没有收到数据,接下来就不会再发数据了。

非应答函数如下,就是拉高SDA:

不产生应答IIC_nAck()

//==================================//不产生ACK应答//用于读取模式(SDA为in)读了8位器件数据后,在第9位给出一个应答,我不想读了//==================================void IIC_NAck(void){ IIC_SCL=0; //确保时钟线为低时,数据线才能变化为0,否则这就可能成起始信号了! SDA_OUT(); //SDA由读取改为发送 IIC_SDA=1; //拉高SDA,表示不应答 delay_us(2); IIC_SCL=1; //SCL先上升 delay_us(2); IIC_SCL=0; //SCL再下降,形成一个脉冲,不应答才生效}

IIC发送一个字节

//==================================//IIC发送一个字节//返回从机有无应答//1,有应答//0,无应答//==================================void IIC_Send_Byte(u8 txd){ u8 t; SDA_OUT(); //SDA发送模式 IIC_SCL=0; //拉低时钟开始数据传输 for(t=0;t《8;t++) { IIC_SDA=(txd&0x80)》》7; //SDA高低电平表示数据1和0 txd《《=1; delay_us(2); //对TEA5767这三个延时都是必须的 IIC_SCL=1; //SCL先上升 delay_us(2); IIC_SCL=0; //SCL再下降,形成一个脉冲,发送一位数据生效 delay_us(2); }}

发送一个字节,就是分8次循环,产生8个时钟信号,并将SDA赋值为0或1。

IIC读取一个字节

//==================================//读1个字节//ack=1时,发送ACK,ack=0,发送nACK //==================================u8 IIC_Read_Byte(unsigned char ack){ unsigned char i,receive=0; SDA_IN(); //SDA输入模式 for(i=0;i《8;i++ ) { IIC_SCL=0; //SCL先下降,通过循环,形成时钟脉冲 delay_us(2); IIC_SCL=1; //SCL上升 receive《《=1; if(READ_SDA) receive++; //读取并组合记录数据,++表示读到1了,最低位置1 delay_us(1); } //读取8位后,主机需要变为发送模式,在第9位进行应答或不应答 //此时CLK还是高电平状态,不过下面的应答会先将CLK拉低的 if (!ack) { //读1个字节,或读多个字节读到最后一个字节时,使用nACK //然后配合使用IIC停止信号 IIC_NAck();//发送nACK } else { //读多个字节还没读完时,使用ACK,表示现在读的ok,还要继续读 IIC_Ack(); //发送ACK } return receive;}

读取一个字节,也是分8次循环,产生8个时钟信号,并读取SDA的高低电平信号,最后,根据要不要继续读下一个字节,发送第9位的Ack或nACK。

4真实IIC波形详细分析

4.1 读取从机数据(单字节读)

下面这张图(请横屏观看)展示IIC读某个器件的寄存器的一个字节的真实波形(注:实际是读了2个不同寄存器的值,每个寄存器读了1个字节,所以,可以先只看前半部分哦~),我已对波形进行了详细的注解,并留意一下颜色区分。

对照着图,再来温习一下各个信号的特点:

起始信号:时钟线SCL为高时,数据线SDA由高到低

停止信号:时钟线SCL为高时,数据线SDA由低到高

数据信号:连续的8位,每一个SCL脉冲时钟对应的SDA,高电平为数据1,低电平为数据0

应答信号:第9位(数据信号后),由对方产生的回应,0为产生回应,1为不产生回应

上面这幅图中,单片机先产生起始信号,然后发送7位器件地址+1位写标志(绿色的0),并等待从机回应(从机拉低SDA表示收到数据),接着发送8位寄存器地址,并等待从机回应。然后,单片机先再次产生起始信号,发送7位器件地址+1位读标志(绿色的1),并等待从机回应。从机收到读的信号后,从机开始发送8位数据,主机接收到数据后,主机发送nAck不应答信号(图中的Ack(1),主机将SDA拉高,从机则认为主机刚才没有收到它发送的数据,从机将不再继续发送),接着主机发送结束信号,读取完成。

此图后半部分是以相同方式读了另一个寄存器的值。

另外,SCL信号都是由单片机产生,SDA信号由单片机和IIC器件(从机)共同产生,当需要对IIC器件的寄存器写时,单片机产生SDA数据,当需要读取IIC器件的寄存器数据时,改变传输方向,IIC器件产生SDA数据。

对于主机和从机什么时候控制SDA,还可以参考这个图帮助理解:

4.2 读取从机数据(多字节读)

上面是单字节读的波形,再来看看多字节的波形,前面的写器件地址、写寄存器地址1与单字节读一样,这张图只显示了后面不一样的部分,主要区别在于单片机接收到数据1后,产生低电平的应答,从而可以继续读取数据2。

(注意,因为传感器这次测得的数据不一样,所以读出的数据也不一样哦~)

注:以上的IIC真实波形,是使用是硬件IIC,自己编写的软件IIC测得的波形,可能在两个信号的前后延时时间上稍有差别,但整体的时序逻辑肯定是一样的。

4.3 配置从机寄存器(单字节写与多字节写)

对于寄存器的配置,也就是IIC的写寄存器操作,我就不放图了,参考上面的“常用的数据收发方式(时序)”以及上面的IIC读寄存器的真实波形,IIC的写寄存器的真实波形,应该可以脑补出哦,哈哈~
编辑:lyn

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

    关注

    6074

    文章

    45342

    浏览量

    663737
  • IIC
    IIC
    +关注

    关注

    11

    文章

    308

    浏览量

    40388

原文标题:从IIC实测波形入手,搞懂IIC通信

文章出处:【微信号:zhuyandz,微信公众号:FPGA之家】欢迎添加关注!文章转载请注明出处。

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

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    基于hbirdv2-sdk的iic 0.96寸lcd调试

    一.前言 简介: 基于hbird-sdk的硬件IIC控制 0.96寸lcd. 二.工程结构 硬件: mcu200t fpga开发板 软件结构: 主要由Makefile main.c
    发表于 10-30 06:20

    iic中只设置了时钟和数据引脚没有配置那个端口,rtt是怎么知道在那个端口上进行iic通信的?

    用的5.2.0版本配置了iic的时钟和数据引脚没有配置端口,系统是怎么判断使用的那个端口的那个引脚开始了通信呢?在rt——thread中需要us的延时么?那个大佬解答一下啊,刚接触这个东西,感谢感谢
    发表于 09-26 07:26

    【微五科技CF5010RBT60开发板试用体验】硬件IIC点亮OLED小屏幕

    ); } return errcode; } 三、实测性能与体验 刷新速度显著提升: * **硬件 IIC (实测):** 在 400kHz 时钟下,理论传输 1024 字节数据时间约为 `(1024 * 9
    发表于 08-08 11:01

    如何FX2LP设备的EEPROM读取固件(.iic)?

    是否有任何工具可以 FX2LP 设备的 EEPROM 读取固件(.iic)? 我想备份旧固件来重新编程我的设备,但我丢失了旧的 IIC 固件。
    发表于 05-07 06:37

    IIC接口的IIC_SCL和IIC_SDA引脚做普通GPIO,程序启动不起来怎么解决?

    想用IIC接口的IIC_SCL和IIC_SDA引脚做普通GPIO,两个引脚对应的是GPIO58和GPIO59,更改代码将设置为普通GPIO引脚模式后,程序启动不起来。问:这种情况如何解决,官方支持这种应用吗?
    发表于 05-06 08:59

    ZYNQ FPGA的PS端IIC设备接口使用

    zynq系列中的FPGA,都会自带两个iic设备,我们直接调用其接口函数即可运用。使用xilinx官方提供的库函数,开发起来方便快捷。
    的头像 发表于 04-17 11:26 1756次阅读
    ZYNQ FPGA的PS端<b class='flag-5'>IIC</b>设备接口使用

    巨霖科技IIC Shanghai 2025精彩回顾

    近日,全球半导体行业瞩目的国际集成电路展览会暨研讨会(IIC Shanghai 2025)在上海金茂君悦大酒店盛大开幕。
    的头像 发表于 03-28 11:27 876次阅读

    为什么IIC总线会难住这么多人?

    为什么 IIC 总线让很多人头疼?其实可以把它想象成一场复杂的 "设备对话游戏",新手容易在这些地方栽跟头:
    的头像 发表于 03-12 10:14 814次阅读
    为什么<b class='flag-5'>IIC</b>总线会难住这么多人?

    使用FPGA控制DLPC3438,采用IIC协议进行读写操作,读取的数据存在错误,无法正确寄存器中读取数据怎么解决?

    规定的字节数一致? (2)FPGA控制IIC读数据按照如下协议,但是读取的数据存在错误,无法正确寄存器中读取数据。 (3)下图为FPGA的IIC读时序,请帮忙查看是否是FPGA的时序存在
    发表于 02-24 07:47

    DLPC3435 IIC通信时候会干扰到DLPC3435正常工作,导致显示花屏或者画面不动怎么解决?

    IIC通信导致DLPC3435出现BUG,导致花屏。 想提问题的是:IIC通信真的会干扰到DLPC3435吗?如果真的是这样要如何规规避这个问题呢?
    发表于 02-21 09:53

    DLPC350怎么才能实现iic通讯?

    我想通过单片机iic接口控制DLPC350,地址是0x34和0x35,然后对对应寄存器进行读写,设置的频率是100khz,但是发现无法通讯上,我想知道怎么才能实现iic通讯?
    发表于 02-21 08:07

    使用IIC通过API给DLPC3479发送控制指令时无应答是什么原因导致的?如何解决?

    1. 使用的是模拟IIC,通过API调用最基本的读取DeviceID命令,但是在第一步写地址 0x36后就没有收到应答信号,请问应该怎么排查?波形图如下,请问有什么因素可能会导致这个
    发表于 02-18 08:16

    DLPC3479 IIC通讯异常的原因?

    ,在发送0x36后无应答; 3. 使用另外买的USB转IIC模块,无法正常连接GUI,通过工具发送指令能读但是读的数据对不上,有误; 请问以上问题有可能是什么原因造成的,应该哪些方面排查?是否有IIC能直接使用的类似GUI的
    发表于 02-18 07:04

    DLPC3479主芯片的IIC1是1.8V,与DLPC3479芯片的IIC0 3.3V直接相连,会不会导致主芯片IIC1引脚出现问题?

    在dlp4710evm-lc _sch参考原理图里,DLPC3479主芯片的IIC1是1.8V,与DLPC3479芯片的IIC03.3V直接相连,这个会不会导致主芯片IIC1引脚出
    发表于 02-17 06:27

    请问DS90UB903Q的IIC工作频率必须为100KHz吗?

    的实际工作与配置相同;使用示波器抓取IIC读ID的波形,发现IIC在写入8位地址0xB0后,没有ACT信号芯片返回。 请问DS90UB903Q的I
    发表于 12-26 07:08