I2C通讯协议详解

Anna ·
更新时间:2024-11-14
· 768 次阅读

I2C协议总结两个方面物理层电气特性协议层I2C基本读写过程#写过程通讯复合格式通讯信号的判断通讯的起始和停止信号数据有效性地址及数据方向响应信号通讯过程部分代码讲解总结**顺便找一下玩过stm32+ESP8266+onenet的大佬** 两个方面

不知道大家是不是有我这种情况,学完STM32之后,感觉学了个寂寞。

大佬说的话听都听不懂,所以复习一波深入了解一下原理
在这里插入图片描述
今天要说的就是I2C通讯协议,刚学不知道这些协议是干嘛用的,了解了之后才发现,不得不会呀,就比如OLED mpu6050 EEPROM巴拉巴拉巴拉。。。总之就是很常用。好了废话说完了。
我们从两个方面来介绍I2C协议
1–>物理层
2–>协议层

物理层电气特性

在这里插入图片描述
1: 它是一个支持多设备的总线,总线的意思就是多个设备共用的信号线,一个总线中可以挂载多个设备。

2: 包括两条总线,即串行时钟线(SCL)C代表clock的意思就是时钟,以及串行数据线(SDA)D代表Data也就是数据的意思。顾名思义,SDA用来传输数据,而SCL用来保持收发同步。

3: I2C总线上可以挂载多个设备,那么是怎么来确认发到哪个从机上呢?**其实每个设备在I2C总线上都有自己的地址,来确保不同设备之间访问的准确性。**地址可以是7位或者11位。

4: 总线通过上拉电阻接到电源。这一点可能很多人不了解,我对照着上面的图详细说一下。在计算机逻辑里:
高电平代表 1 (高阻态)
低电平代表 0
在设备空闲或者输出1时,我们输出的并不是高电平而是高阻态!
在这里插入图片描述

高阻态,顾名思义嘛,电阻很大,那么就取无穷大喽。
表示空闲状态时假设图中触摸屏空闲时输出零电压, SCL总线就会被拉低,此时如果传感器 工作,输出一个高电平,此时的触摸屏是0V,传感器是高电平,就会造成短路。如果我们给触摸屏一个高阻态,相当于断路。此时我们令传感器的电压为高电平,那么整个SCL总线就被拉高了。

**表示高电平时:**假设其他设备空闲(高阻态),就可以忽略了,只有传感器工作,如果输出高阻态,又由于存在上拉电阻,所以整个SCL线也就是1。

5: 具有三种传输模式:标准模式传输速率为 100kbit/s ,快速模式为 400kbit/s ,高速模式下可达 3.4Mbit/s,但目前大多 I 2C 设备尚不支持高速模式。我们一般就使用标准模式就可以了。

6: 连接到相同总线的 IC 数量受到总线的最大电容 400pF 限制 。
PS: 纯属被迫营业,没学过电路

在这里插入图片描述

协议层

I2C 的协议定义了通讯的起始和停止信号、数据有效性、响应、仲裁、时钟同步和地址广播等环节。通过总线的状态来表述不同的信号。

I2C

I2C基本读写过程

先放一张图:
在这里插入图片描述

#写过程

先不用了解具体怎么产生的信号,先来抽象地理解一下,拿写来说:
主机先说一句开始传输(S),传输到哪呢??很明显就是从机了(ADRESS),主机再次确认是读别人数据还是写数据呢(R/W),然后从机表示晓得了你要读/写(A),主机发送数据巴拉巴拉巴拉,发送完成之后,从机表示不接受数据了(非应答 那个符号不会打).然后主机停止写数据(P)。
--------------------------------------- 原谅我的文笔,太感人了。----------------------------------------------
在这里插入图片描述

S: 表示开始传输,先说一声开始。
SLAVE_ADDRESS: 这个图上也有说,就是从机地址
R/W: 0为写,1为读
DATA: 发送的数据
A: 应答信号
P: 停止信号。结束了

通讯复合格式

在这里插入图片描述
这个过程其实和前面讲的写过程差不多,假设第一个R/W是写,那么主机先产生开始信号,找到从机地址,开始写,从机应答,此时后边的这个DATA表示的是要写的从机的地址,比如EEPROM,写到哪里呢,就是由这个DATA决定的,后边的都差不多就不啰嗦啦。

通讯信号的判断 通讯的起始和停止信号

在这里插入图片描述
1 当SCL为高电平,SDA从高变为低,表示起始信号
2 当SCL为高电平,SDA从低变高,表示停止信号

数据有效性

在这里插入图片描述
1: 当SCL为高电平时,如果SDA为高电平,表示数据1,如果SDA为低电平,表示数据0.
2 当SCL为低,SDA进行电平转换,表示传输下一个数据。

地址及数据方向

在这里插入图片描述
前面我们说到地址为7位或者10位,一般都用七位。
八位设备地址=7位从机地址+读/写地址,以EEPROM为例,他的七位设备地址为1111000十六进制转换之后就是0x78
八位设备的读地址=1111 0001=0xF1
八位设备的写地址=1111 0000=0xF0

响应信号

在这里插入图片描述
在传输时,主机产生时钟,在产生的第九个时钟时(8个时钟8个字节,就穿输了一个位(byte)了)
数据发送端就会放弃对SDA的控制权,转为数据接收端控制SDA,此时若为低电平则为应答,高电平为非应答

通讯过程

在这里插入图片描述
在这里插入图片描述
这里就不多说了,了解完前面看这里就很轻松,上面的和读写过程基本一样。在这里插入图片描述
需要特别说的就是下面的EV5,EV6之类的了,其实下面的表示的是状态,比如产生一个起始信号,就会有对应的事件产生,如果此时我们检测状态寄存器(想了解的可以参加《STM32中文参考手册》),如果检测到事件发生,就判断产生了起始信号,算是一个保障吧。

部分代码讲解 #include "myiic.h" #include "delay.h" void IIC_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE ); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7); } void IIC_Start(void) { SDA_OUT(); //sdaÏßÊä³ö IIC_SDA=1; IIC_SCL=1; delay_us(4); IIC_SDA=0;//START:when CLK is high,DATA change form high to low delay_us(4); IIC_SCL=0; } //²úÉúIICÍ£Ö¹ÐźŠvoid IIC_Stop(void) { SDA_OUT();//sdaÏßÊä³ö IIC_SCL=0; IIC_SDA=0;//STOP:when CLK is high DATA change form low to high delay_us(4); IIC_SCL=1; IIC_SDA=1; delay_us(4); } u8 IIC_Wait_Ack(void) { u8 ucErrTime=0; SDA_IN(); IIC_SDA=1;delay_us(1); IIC_SCL=1;delay_us(1); while(READ_SDA) { ucErrTime++; if(ucErrTime>250) { IIC_Stop(); return 1; } } IIC_SCL=0;//ʱÖÓÊä³ö0 return 0; } void IIC_Ack(void) { IIC_SCL=0; SDA_OUT(); IIC_SDA=0; delay_us(2); IIC_SCL=1; delay_us(2); IIC_SCL=0; } void IIC_NAck(void) { IIC_SCL=0; SDA_OUT(); IIC_SDA=1; delay_us(2); IIC_SCL=1; delay_us(2); IIC_SCL=0; }

IIC_Start(); 起始信号
IIC_Stop();停止信号
IIC_Wait_Ack(); 等待应答
IIC_Ack()应答信号
IIC_NAck 非应答信号
这些根据前面的时序图理解就可以了;

着重讲一下发送与读取字节的函数

void IIC_Send_Byte(u8 txd) { u8 t; SDA_OUT(); IIC_SCL=0;//À­µÍʱÖÓ¿ªÊ¼Êý¾Ý´«Êä for(t=0;t>7; txd<<=1; delay_us(2); //¶ÔTEA5767ÕâÈý¸öÑÓʱ¶¼ÊDZØÐëµÄ IIC_SCL=1; delay_us(2); IIC_SCL=0; delay_us(2); } } //¶Á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; delay_us(2); IIC_SCL=1; receive<<=1; if(READ_SDA)receive++; delay_us(1); } if (!ack) IIC_NAck();//·¢ËÍnACK else IIC_Ack(); //·¢ËÍACK return receive; }

先看发送数据 txd为要发送的数据,0x80就是1000 0000
如果txd第一位为1,则 txd&0x80=1000 0000
如果txd第一位为0 则 txd&0x80=0000 0000 这个与运算的作用就是提取txd最高位的数据;
(txd&0x80)>>7 表示(txd&0x80)右移七位 ,假设数据是1000 0000右移后补零就是0000 00001,
这样就得到了最高位(第八位)的数据;之后令数据左移一位,循环得到第七位的数据
接受数据的同理。

总结

经过最近学习发现通讯真的很重要,前几天做了关于OLED 和mpu6050的实验,都是用的I2C通讯协议。ESP8266连接云服务器也要用的协议(MQTT)。一定要把通讯吃透哦,不然后期很难学的。
在这里插入图片描述
在了解完这些之后代码大部分就可以看懂了,其中I2C的初始化之类的东西我就不说了哈,大家有兴趣可以采用I2C通讯协议与EEPROM进行通讯。

如果学到的话,麻烦各位看官老爷点个赞再走吧,ball ball 你们了。
在这里插入图片描述

顺便找一下玩过stm32+ESP8266+onenet的大佬

在这里插入图片描述


作者:瓶邪!·



协议 i2c

需要 登录 后方可回复, 如果你还没有账号请 注册新账号