当前位置: 首页 > news >正文

【STM32开发之寄存器版】(十二)-I2C基础知识详解

一、前言

本文主要参考了NXP恩智浦公司发布的UM10204_I2C-bus specification and user manual,该手册详细介绍了I2C通讯协议的设计和使用规范。

为了深入理解I2C的时序逻辑,本文并不选择使用STM32F103ZET6的硬件I2C,而是使用软件模拟I2C。本文着重介绍I2C的基础知识,为I2C读取MPU6050六轴惯性传感器打好基础。

二、I2C基础知识

2.1 I2C简介

在普通消费电子领域,几乎每个系统都包括控制系统(如MCU)、通用电路(如EEPROM、AD/DA转换器)、面向应用的电路(如信号处理电路、温度传感器)。为了保证通讯接口的相似性,最大限度提升硬件效率和电路的简洁性。Philips Semiconductors (现在的NXP Semiconductors)开发了一种简单的双向双线总线,用于不同IC之间的高效控制,这种总线被命名为I2C总线。I2C总线的设计理念解决了设计数字控制电路时遇到的很多接口问题,其电路应用场景如下图所示:

2.2 I2C的主要特性

I2C总线具备以下特性:

  • 只需要两条总线;一条串行数据线(SDA)和一条串行时钟线(SCL)
  • 连接到总线的每个设备都可以通过一个唯一的地址进行软件寻址,控制器既可以作为发送端也可以作为接收端使用。
  • 属于多控制器总线,如果多个控制器同时启动数据传输,可以进行碰撞检测和仲裁,以防止数据损坏。
  • 一种串行的双向数据传输总线,一般包含8个数据位。在标准模式下传输速度高达100Kbps快速模式下传输速度高达400Kbps,快速Plus模式下传输速度高达1Mbps,高速模式下传输速度高达3.4Mbps。
  • 可连接到同一总线的IC数量仅受最大总线电容的限制(一般来讲标准模式负载电容不超过400pF,快速模式负载电容不超过200pF)。

2.3 I2C硬件结构分析

2.3.1 I2C硬件接线方式

I2C一般包含VDD、VSS、SCL和SDA这四根线,SCL和SDA需要通过上拉电阻Rp与VDD相接,如下图所示:

2.3.2 I2C IO口配置

I2C协议规定,连接到总线的设备必须将IO口配置为开漏模式(OD)开集模式(OC),这两种模式可以执行 线与 功能。以STM32为例,配置为开漏模式后,GPIO内部原理图如图所示:

开漏模式下的GPIO内部相当于一个NMOS直接接地。此时,配置为开漏模式的GPIO只有两种状态:低电平和高阻态。当内部NMOS的G极为低电平,NMOS关闭,IO状态为高阻态。当内部NMOS的G极为高电平,NMOS开启,IO状态为低电平。此时的IO口无法获得高电平状态,不能满足I2C通讯协议的电平要求(I2C电平要求:高电平大于0.7VDD,低电平低于0.3VDD)。因此需要外接上拉电阻获得高电平状态

此时,当内部NMOS的G极为低电平,NMOS关闭,IO状态为高阻态,但由于外部上拉电阻的作用,I2C信号线上的电平为高电平,Multisim仿真如下图所示:

当内部NMOS的G极为高电平,NMOS开启,IO状态为低电平,I2C信号线上的电平为低电平,Multisim仿真如下图所示:

综上所述,在OD模式下,SCL或SDA通过外部上拉电阻获得正常的高低电平信号。 

2.3.3 线与逻辑 

在存在多控制器的I2C总线上,开漏模式下的GPIO很容易组成“线与逻辑”,当多个SCL或SDA中有某一个处于逻辑“0”,状态,就会将整个线路置为低电平,由此可以实现多控制器下的时钟同步和数据仲裁(本文不再详细介绍)。

当多线路的逻辑均为高电平时,该条线路有效电平为高(1&1&... ... &1 = 1)。 Multisim仿真如下图所示:

当多线路的逻辑中某些为低电平,该条线路有效电平为低(1&...&0& ... &1 = 0)。 Multisim仿真如下图所示:

2.3.4 I2C上拉电阻计算

由2.3.2可知,上拉电阻对于实现I2C通讯的高电平逻辑非常关键。但上拉电阻的阻值并不是随意选取的。

2.3.4.1 上拉电阻最大值

I2C总线电容包含导线电容、连接器电容以及引脚电容,总线电容通过影响信号上升时间限制了上拉电容的最大值。为了计算上拉电容的最大值,需要考虑时间常数RC对于信号上升时间的影响,联立以下3式:

\begin{cases} V_{IH}=0.7V_{DD}\\ V_{IL}=0.3V_{DD}\\ V\left( t \right) =V_{DD}\left( 1-e^{-\frac{t}{RC}} \right)\\ \end{cases}

其中,VIH为信号有效高电平阈值,VIL为信号有效低电平阈值。RC为时间常数,VDD为上拉电阻供电电压。联立结果可得:

\begin{array}{l} \mathrm{V(t}1)=0.3\times \mathrm{V}_{\mathrm{DD}}=\mathrm{V}_{\mathrm{DD}}(1-\mathrm{e}^{-\mathrm{t}1/\mathrm{RC}});\mathrm{t}1=0.3566749\times \mathrm{RC}\\ \mathrm{V(t}2)=0.7\times \mathrm{V}_{\mathrm{DD}}=\mathrm{V}_{\mathrm{DD}}(1-\mathrm{e}^{-\mathrm{t}2/\mathrm{RC}});\mathrm{t}2=1.2039729\times \mathrm{RC}\\ t_r=\mathrm{t}2-\mathrm{t}1=0.8473\times \mathrm{R}_{p\left( \max \right)}\mathrm{C}_b\\ \end{array}

其中,Rp(max)为上拉电阻最大值,Cb为总线电容。由此可以得到上拉电阻最大值

R_{p(max)}=\frac{t_r}{0.8473\times C_b}

在标准模式、快速模式和快速模式PLUS下,I2C总线协议对总线电容Cb的要求如下: 

在标准模式、快速模式和快速模式PLUS下,I2C总线协议对上升时间tr的要求如下: 

在标准模式、快速模式和快速模式PLUS下,上拉电阻最大值与总线电容Cb之间的关系图如下:

2.3.4.2 上拉电阻最小值

电源电压VDD通过影响引脚灌电流(sink current)进而限制了上拉电阻的最小值。在标准模式、快速模式和快速模式PLUS下,I2C总线协议对引脚灌电流的要求如下: 

上拉电阻最小值可以按照如下公式进行计算:

R_{p(min)}=\frac{V_{DD}-V_{OL(max)}}{I_{OL}}

2.3.5 I2C layout guidence

一般来说,在布线时必须尽量减少总线线路之间的串扰和干扰。总线线路在高电平时最容易受到串扰和干扰,因为上拉器件的阻抗相对较高。

如果印刷电路板上的总线线路长度超过 10 厘米,且包括 VDD 和 VSS 线路,则布线模式应为:

若仅仅包含VSS线路,则布线模式应为:

这种布线模式可以使 SDA 和 SCL 线路具有相同的电容负载。

  • 如果使用多层PCB(其中包含单独的VSS或VDD层),则可以省略 VSS 和 VDD 线路。
  • 如果总线线路是双绞线,则每条总线线路都必须与 VSS 回线绞合。或者,SCL 线与 VSS 回线绞合,SDA 线与 VDD 回线绞合。后者必须使用电容器在扭绞线对的两端对 VDD 线路与 VSS 线路去耦。
  • 如果对总线线路进行屏蔽(屏蔽层与 VSS 相连),则可将干扰降至最低。不过,屏蔽电缆的 SDA 和 SCL 线路之间必须具有低电容耦合,以尽量减少串扰。

2.4 I2C时序逻辑分析

对于I2C的时序逻辑分析主要包括数据有效性、开始/停止信号、字节格式、应答/非应答信号。本文对于I2C时序逻辑分析主要以I2C的标准模式为例。

2.4.1 数据有效性

在SCL时钟的高电平期间,SDA 线路上的数据必须保持稳定大于5us只有当 SCL 线上的时钟信号处于低电平时,数据线的高电平或低电平状态才能发生变化。每传输一个数据位会产生一个时钟脉冲。具体时序逻辑如下图所示。

2.4.2 开始/停止信号

所有传输都以 START (S) 开始,以 STOP (P) 结束。当 SCL 为高电平时,SDA 线上从高电平到低电平的转换定义为启动条件当 SCL 为高电平时,SDA 线路上从低电平到高电平的转换定义了 STOP 条件。

开始信号时序逻辑如下所示: 

停止信号时序逻辑如下所示: 

2.4.3 字节格式

SDA 的每个字节长度必须为 8 位。每次传输的字节数不受限制。每个字节后必须有一个确认位。数据传输时,最高位 (MSB) 优先。如果接收端在执行其他功能(例如处理内部中断)之前无法接收或传输一个完整字节的数据,它可以将时钟线 SCL 保持在低电平,迫使发送端进入等待状态。当接收端准备好接收一个字节的数据并释放时钟线 SCL 时,数据传输将继续进行。时序逻辑如下图所示:

2.4.4 应答/非应答信号

每个字节之后都要进行应答。应答位允许接收器向发送器发出信号,表明已成功接收字节,可以发送另一个字节。

应答信号的定义如下:发送器在应答时钟脉冲期间释放 SDA 线,以便接收器将 SDA 线拉至低电平,并在该时钟脉冲的高电平期间保持稳定的低电平。

应答信号的时序逻辑如下所示:

当 SDA 在第九个时钟脉冲期间保持高电平时,这被定义为 “非应答 ”信号。此时,控制器可产生一个停止(STOP)条件以中止传输,或产生一个重复开始(START)条件以开始新的传输。有五种情况会导致产生 NACK:

1. 传输地址的总线上没有接收器,因此没有设备响应确认。
2. 接收器无法接收或发送,因为它正在执行某些实时功能,尚未准备好开始与控制器通信。
3. 在传输过程中,接收器收到了它无法理解的数据或命令。
4. 在传输过程中,接收器无法接收更多数据字节。
5. 控制器-接收器必须向目标发送器发出传输结束信号。

非应答信号的时序逻辑如下所示:

2.5 I2C目标地址与读写位

在启动条件 (S) 之后,会发送一个目标地址。数据传输总是由控制器产生的停止条件 (P) 终止。但是,如果控制器仍希望在总线上进行通信,它可以重复产生一个 START(开始)条件 (Sr),并寻址另一个目标,而无需先产生一个 STOP(停止)条件。这样就可以在传输过程中实现各种读/写格式组合。数据传输格式如下图所示。

目标地址长度为 7 位,后面的第 8 位为数据方向位 (R/W)--“0 ”表示传输(写入),“1 ”表示数据请求(读取),如下图所示:

例如:当六轴姿态传感器MPU6050的AD0脚(用于确认地址的引脚)为0时,此时MPU6050的I2C目标地址为0b1101000(共7位),对MPU6050执行写入操作时,命令为0b11010000(0XD0),对MPU6050执行读取操作时,命令为0b11010001(0XD1)。

2.6 I2C读写逻辑分析

I2C 通信流程按照以下步骤进行:

  • 主控向总线发送开始信号。
  • 主控将要通信的设备地址和读写位(R/W)发送到总线上。
  • 设备接收到地址后发送应答信号,主控接收到应答信号后发送数据或继续发送地址。
  • 设备接收到数据后发送应答信号,主控接收到应答信号后可以继续发送数据或者停止通信。
  • 主控向总线发送停止信号。

I2C发送数据流程如下: 

I2C接收数据流程如下: 

三、软件模拟I2C

软件模拟I2C主要包括起始信号、停止信号、等待应答信号到来、产生应答信号、产生非应答信号、I2C发送一个字节、I2C读取一个字节。具体代码如下所示:

//产生IIC起始信号
void IIC_Start(void)
{SDA_OUT();IIC_SDA=1;	  	  IIC_SCL=1;delay_us(5);IIC_SDA=0;delay_us(5);IIC_SCL=0; delay_us(5);
}	  
//产生IIC停止信号
void IIC_Stop(void)
{SDA_OUT();IIC_SCL=0;IIC_SDA=0;delay_us(5);IIC_SCL=1; delay_us(5);IIC_SDA=1;delay_us(5);							   	
}
//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
u8 IIC_Wait_Ack(void)
{u8 ucErrTime=0;SDA_IN();      //SDA设置为输入  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;  
} 
//产生ACK应答
void IIC_Ack(void)
{SDA_OUT();IIC_SDA=1;IIC_SCL=0;delay_us(2);IIC_SDA=0;IIC_SCL=1;delay_us(5);IIC_SCL=0;IIC_SDA=1;
}
//不产生ACK应答		    
void IIC_NAck(void)
{SDA_OUT();IIC_SDA=0;IIC_SCL=0;delay_us(2);IIC_SDA=1;IIC_SCL=1;delay_us(5);IIC_SCL=0;IIC_SDA=0;
}					 				     
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答			  
void IIC_Send_Byte(u8 txd)
{                        u8 t;   SDA_OUT(); 	    IIC_SCL=0;for(t=0;t<8;t++){              IIC_SDA=(txd&0x80)>>7;txd<<=1; 	  delay_us(2);  IIC_SCL=1;delay_us(5); IIC_SCL=0;	delay_us(5);}	 
} 	    
//读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();//发送nACKelseIIC_Ack(); //发送ACK   return receive;
}

http://www.mrgr.cn/news/55182.html

相关文章:

  • 每日OJ题_牛客_[NOIP2001]装箱问题_01背包_C++_Java
  • Qt5.14.2 安装详细教程(图文版)
  • IP池与代理池的区别
  • ApacheShiro反序列化 550 721漏洞
  • Parade Series - Win11 YOLO v5
  • 双ll将至,你找到好用的API接口获取商品详情数据吗?
  • 前后端联调需要改ip联调多个后端,用nginx代理
  • QT5升级到QT6后遇到的问题
  • Bitmap 和 布隆过滤器傻傻分不清?你这不应该啊
  • 聚焦IOC容器刷新环节postProcessBeanFactory(BeanFactory后置处理)专项
  • SVN 小乌龟 下载地址
  • Git 基本配置
  • nodejs基础(2)
  • 同步和异步路由
  • 【网络安全的神秘世界】Python 3.7安装教程
  • C++实现简易JSON解析与转储
  • 电磁兼容(EMC):趋肤效应在PCB设计中的应用详解
  • DataGrip导出MySql提示无权限errno 13 - Permission denied问题
  • 使用Milvus和Llama-agents构建更强大的Agent系统
  • Mybatis扩展
  • Dockerfile 中,把多个 RUN 合并在一起,能减少镜像尺寸吗?
  • 特斯拉自动驾驶出租车计划变成泡影?联想与Meta合作,推出面向PC的个人AI智能体AI Now|AI日报
  • 学生学籍管理系统设计与实现(源码+定制+开发)
  • Varchar(255)可以存255个汉字
  • 为什么互动投影墙在儿童展馆中如此受欢迎?创新互动是关键吗?
  • 【AIGC】ChatGPT提示词Prompt高效编写模式:Self-ask Prompt、ReACT与Reflexion