学习笔记–stm32I2C通信
目录
一、IIC协议
1.1 简介
1.2 I2C物理层
1.3 I2C主要特点
1.4 总结
二、I2C时序基本单元
2.1起始条件
2.2终止条件
2.3发送一个字节
2.4接收应答
2.5接收一个字节
2.6发送应答
三、I2C时序
3.1指定设备指定地址写
3.2指定设备当前地址读
3.3指定设备指定地址读
一、IIC协议
1.1 简介
IIC通讯协议(Inter IC BUS,习惯叫I2C)是由Philip飞利浦公司开发的,由于它所需引脚少,硬件实现简单,可拓展性强,广泛用于系统内多个集成电路IC(芯片)间的通讯。
这里对比一下串口通信:
串口通信也是两根信号线,依靠异步通信实现了全双工(即设备之间约定好通信速度);I2C则是拿其中一根信号线用来同步时钟,实现了半双工 异步的缺点是依赖硬件支持,数据传输出现暂停时,接收方是不知道的;而同步则相反,不依赖硬件(这也是大家喜欢模拟IIC的原因),数据传输可以暂停 串口通信的收发设备双方在传输数据时彼此之间没有应答机制,均不知道对方是否收到了数据,I2C则规定了应答 串口通信没有主机从机的概念,因为绑定了传输数据的对象,I2C则是多主多从,只要是挂载到信号线上的设备,都可以实现通信 比喻一下:串口通信传输数据的方式就像是不用言说、忠贞不渝的夫妻,I2C则是一个公共邮筒,需要通信的双方通过书信往来(当然会署名,收到才回信)
1.2 I2C物理层
它是一个支持多设备通信的总线。“总线”指多个设备共用的信号线,一条SDA(双向串行数据线)、一条SCL(串行时钟线)。数据线用来传输数据,时钟线用来同步设备之间数据的收发。每个设备的数据线、时钟线都对应挂在总线上。
1.3 I2C主要特点
为了方便通常把I2C设备分为主设备和从设备,谁控制时钟线(即控制SCL的高低电平变换)谁就是主设备。
这里涉及到「开漏输出」、「上拉电阻」和「线与」三个概念。这对于I2C总线协议绝对是关键所在。因为有那么多的设备,仅仅通过这两根总线来进行通信,哪个时刻谁发谁收,很容易乱。
开漏输出和上拉电阻
在芯片中,当输出为漏极开路(OD)或集电极开路(OC)时,简称开漏输出,它只能输出低电平和高阻态(可理解为开路,阻抗无穷大)。(这其实就避免了主从设备都输出高电平时导致短路的问题)
正因此,开漏输出好比「要么拉低要么放手」,使得设备要想使用总线只能输出低电平来占用总线,从而实现了「线与」的功能,「线与」就是逻辑与,输入有若干个,这里想表达的意思是——当总线上只要有一个设备输出低电平(线与为0),总线便处于低电平状态,称为占用状态。
那高阻态有什么用呢?根据前面的分析,设备只能给总线输出低电平,怎么拉高呢?这时候,上拉电阻就起作用了,简单理解就是上拉电阻可以拉高引脚的电平。当设备输出高阻态,同时没有其他设备占用总线(拉低总线电平),即所有设备都输出高阻态,那么此时总线就会被上拉电阻上拉到高电平称为空闲状态,也实现了「线与」功能(全输入1,才输出1)。
(不能用推挽输出吗?推挽输出不需要上拉电阻,但mos管阻抗小,容易造成短路,而且也实现不了线与)
1.4 总结
物理层上由两根总线SDA(传输数据)、SCL(同步数据收发)以及上拉电阻组成,每个设备的SDA、SCL都挂载在对应总线上。通过默认配置各设备的SDA、SCL为开漏输出,加上上拉电阻,实现了逻辑线与功能。设备要想使用总线,需要输出低电平。当所有设备都输出高电平,总线才表现为高电平。控制占用时钟线的设备为主设备。
二、I2C时序基本单元
2.1起始条件
SCL高电平期间(空闲状态),SDA从高电平切换到低电平,随后,SCL切换到低电平(表示主机开始占用)
2.2终止条件
SCL高电平期间(空闲状态),SDA从低电平切换到高电平
2.3发送一个字节
主机占用SCL,主机依次将数据位放到SDA线上(高位先行),然后主机释放SCL,从机会在SCL高电平期间读取数据位,循环此过程8次,即可发送一个字节数据,
2.4接收应答
主机发送完一个字节后(主机继续占用时钟线),主机释放SDA(等待且允许从机控制数据线),然后主机释放SCL,读取一位数据,用于判断从机是否应答(即是否收到数据),数据0表示应答,数据1表示非应答
(形象地说就是:主机发送完一个字节,问”有没有人收到?我现在松开数据线了哈!如果有人收到,就把数据线拽下来“。接着主机松开时钟线读取SDA。如果主机发现自己松手后,数据线没变化还是高电平,说明从机没收到数据,反之说明从机收到了数据)
2.5接收一个字节
主机占用SCL,主机释放数据线,从机将数据位依次放到SDA线上(高位先行),然后主机释放SCL。主机将在SCL高电平期间读取数据位,循环此过程8次,即可接收一个字节数据
(图中实线代表主机控制,虚线代表从机控制)
2.6发送应答
主机接收完一个字节后(主机继续占用SCL),主机发送一位数据(数据数据0表示应答,数据1表示非应答),主机释放SCL,等待从机读走数据线。如果从机读到了主机的应答,它可以接着向主机发送数据;如果没得到应答,会以为主机接收失败或者主机不需要接收了,这两种情况都需要交出数据线的控制权,对于主机接收失败,主机会重新开始和从机通信;而对于不需要接收了,主机可能会向从机发送其他数据了。
三、I2C时序
主机在和从机通信前,需要进行”点名“,所有从机都会收到第一个字节,这个字节就是某个从设备的地址,所有从设备都会将其和自己的名字进行比较,确认是在叫自己后,该从设备就响应之后主机的读写操作。
有关从机设备的地址,I2C协议标准里分为7位和10位地址(7位地址较为普遍)。
为什么是7位?因为还有1位用来确认主机是要读/写从机。0表示主机将向从机发送数据,1表示主机将向从机接收数据。
每个I2C设备出厂时,厂商都会分配一个默认的7位地址(具体需要查芯片手册),比如某个型号的MPU6050的是1101000,为什么说某个型号呢?因为同一型号的一般来说地址默认的都是一样的,如果实在需要挂载在同一I2C总线下,也有办法解决:7位地址中存在可变部分(具体地以芯片手册为准)。仍以MPU6050为例,最后一位可由模块的AD0引脚确定,当它接低电平时,地址为1101000,接高电平时,1101001
3.1指定设备指定地址写
起始条件后,主机控制时钟线,发送第一个字节用于指定设备+指定写,接收应答,再发送一个字节指定地址(从机内部寄存器的地址),接收应答
主机发送N字节+接收N应答
终止条件
3.2指定设备当前地址读
起始条件后,主机控制时钟线,发送第一个字节用于指定设备+指定读,接收应答
从当前地址开始读N字节,接收N应答
终止条件
当前地址读?哪个当前地址?(因为指定设备时如果指定读,主机就不能再控制数据线,写入要读的地址了)
实际上,从机内部所有的寄存器都被分配到了一个线性区域(可以简单理解成一个线性数组),并且,有一个单独的指针变量,指着其中一个寄存器(其中一个数组元素),这个指针就称为当前地址指针,它上电默认指定数组[0]。每写入一个字节或读出一个字节后,指针会自增一次, 指向下一个寄存器。
比如以3.1中的图片时序为例,在0x19地址下写入了一个字节,如果调用指定设备当前地址读时序,就会读出0x1A的数据,再接着读,读出0x1B的数据……
3.3指定设备指定地址读
3.2的操作虽然有些麻烦,而且通常我们也不这么用,但是!如果只是指定了地址,不写入字节,那么!接下来就可以指定地址连续读!
这就是指定设备指定地址读的思路,一般也称这种时序为复合格式。
起始条件后,主机控制时钟线,发送第一个字节用于指定设备+指定写,接收应答,再发送一个字节指定地址(从机内部寄存器的地址),接收应答(当前地址指针已指向准备写入的寄存器地址)
不发送要写入的字节,转而再发送起始条件,发送第一个字节用于指定设备+指定读,接收应答
往后就可以连续读出N字节数据,发送N字节应答
终止条件(这里需要注意,不打算接着读,在此前要发送非应答,这样从机才知道主机不接着读了!!!)
作者:LateBloomer777