STM32——一文完全读懂IIC通信

2023-10-26

I2C基本概念+硬件线路+通信结构:

概念
I2C是一种串行同步通信协议,用于在集成电路之间进行通信。
硬件路线
I2C使用两根线进行通信:串行数据线(SDA)和串行时钟线(SCL)。
通信结构
I2C使用主从结构,其中主设备发起通信并控制通信的节奏,从设备响应主设备的请求。从机通常不会主动给主机发送数据,一般为主机给从机发送读取指令后,从机才给主机发送数据。器件发送数据到总线上,则定义为发送器,器件接收数据则定义为接收器。主器件和从器件都可以工作于接收和发送状态。
在这里插入图片描述
不能在IIC通信总线上接入无限多个设备的原因:
1.地址冲突:在IIC总线上,每个设备都需要有一个唯一的地址。地址通常由设备的硬件引脚配置。然而,IIC地址字段的宽度有限,这意味着地址空间是有限的。当连接的设备数量超过地址空间的限制时,设备之间可能会出现地址冲突,导致通信失败。
2.总线负载:每个设备在IIC总线上会产生一定的负载。总线的负载是指总线上的所有设备对电流和电压的需求。当连接的设备数量增多时,总线负载会增加,可能导致通信速度变慢或信号失真。
3.电气特性:IIC总线的电气特性是有限的。总线上的设备之间通过开漏或开漏/开漏极性输出进行通信。然而,当连接的设备数量过多时,总线上的电气负载可能超过IIC规范的限制,导致通信错误或电气稳定性问题。
一些基础概念
SDA:双向串行数据线,数据既可以从主机发送到从机,也可以从从机发送到主机。
SCL:串行时钟线,驱动数据线的信号由 SCL 产生。
主机:主机产生串行时钟(SCL)控制总线的传输方向,并产生起始条件(占用总线)和停止条件(释放总线)。
从机:从机不会控制 SCL 线,从机可以发送数据给主机,但是从机永远不可能主动发送数据给主机。
发送器:发送数据的一方 接收器:接受数据的一方 。
仲裁器:解决多主机模式下竞争总线的问题。(通常情况下我们遇到的都是单主机模式,一主多从)
总线的空闲状态:SDA 和 SCL 都是高电平
重复起始条件(一般不提,跟普通通信一样但是能够切换主从机):I2C(Inter-Integrated Circuit)协议中的重复起始条件(Repeated Start Condition)是一种特殊的通信方式,允许在不断开总线的情况下切换主机和从机,并进行连续的数据传输。

I2C设备地址:

主机如何能找到对应的从机与其进行通信?——设备地址
每个I2C设备都有一个唯一的7位或10位地址,用于在总线上唯一标识设备。
7(4、3)位地址模式下,可以有最多128个不同的设备地址(0x00至0x7F)。
10位地址模式下,可以有最多1024个不同的设备地址(0x000至0x3FF)。
器件地址包含固定地址(由厂家决定)和可编程地址(由使用者决定)——参考手册。
7位地址编码方式:
在7位地址编码方式下,从机设备的地址由7个位组成,范围是0x00至0x7F(0至127)。其中,最高位(MSB)通常由I2C总线规范中保留,用于指示读/写操作。读操作对应的最高位为1,写操作对应的最高位为0。
例如,一个从机设备的7位地址为0x50(十进制为80),对应的二进制表示是0101000(其中最高位为读/写位,0表示写操作)。
7位地址编码方式是I2C通信中最常用的方式,适用于大多数应用。
10位地址编码方式:
在10位地址编码方式下,从机设备的地址由10个位组成,范围是0x000至0x3FF(0至1023)。其中,最高两位(MSB)用于指示读/写操作和扩展地址位。
扩展地址位提供了更多的地址空间,可以用于连接更多的从机设备。在10位地址编码方式下,前六位(位7至位2)用于指定扩展地址位,后四位(位1至位0)用于指示读/写操作。
例如,一个从机设备的10位地址为0x235(十进制为565),对应的二进制表示是1000110101(前两位为读/写位和扩展地址位)。
10位地址编码方式相对较少使用,主要用于连接大量的从机设备。
如何寻址?
在I2C通信中,主机设备可以选择与多个从机设备进行通信,每个从机设备都有一个唯一的地址。通过在地址字节中指定正确的从机设备地址,主机可以选择与特定的从机设备进行通信。
7位和10位就是一个从机多一些。
在这里插入图片描述

I2C数据传输:

I2C使用起始条件(Start Condition)和停止条件(Stop Condition)来标识数据传输的开始和结束。
数据传输可以是字节(Byte)级别的,也可以是多字节(Multi-Byte)级别的。
主设备通过将数据位推送到SDA线上发送数据,从设备通过SDA线接收数据。
I2C传输模式:
I2C支持两种传输模式:发送模式(Master Transmit)和接收模式(Master Receive)。
在发送模式中,主设备向从设备发送数据。
在接收模式中,主设备从从设备接收数据。
数据帧格式:
起始条件(占用总线)+数据位(8 位,发送方发出,一般为7位地址位和1位读写位)+应答位(1 位,接收到 1 个字节数据的 一方要回一个应答,0 有应答,1 非应答)+数据传输(8位)+停止条件(释放总线)

I2C时钟速度和通信速度:

I2C通信的时钟速度由主设备控制。
标准模式下,时钟频率为100 kHz。
快速模式下,时钟频率为400 kHz。
高速模式和超高速模式下,时钟频率可以更高,但具体取决于设备和总线的支持能力。
IIC 总线通信速度:
低速:100Kbit/s 快速:400Kbit/s 高速:3.4Mbit/s

I2C应答机制:

在每个数据字节传输后,接收设备会发送应答位(ACK)以确认接收到数据。
如果接收设备成功接收数据,它会拉低SDA线发送ACK信号;如果无法接收或不希望接收,它会保持SDA线为高电平发送NACK信号。
应答的发送和接收:
在这里插入图片描述

I2C设备之间的冲突检测:

I2C总线上的多个设备共享同一对SDA和SCL线。
为了避免冲突,一般使用以下两个方法:

  1. 尽量保持地址唯一性。
  2. 总线仲裁,I2C使用仲裁机制来检测总线上的冲突情况,并由冲突检测的设备放弃发送数据。I2C总线使用开漏架构,这意味着设备可以拉低SDA线,但不能将其拉高。当两个或多个设备同时尝试将SDA线拉低时,发生冲突。在总线仲裁过程中,设备根据自身的地址优先级决定是否继续发送数据或放弃发送,以解决冲突。
    总线仲裁的过程是通过设备对SDA和SCL线的观测来实现的。如果一个设备发送的数据与总线上的数据不匹配,它会立即检测到冲突并停止发送。然后,它会等待总线空闲,并重新尝试发送数据。
  3. 错误重传和硬件检测两个方式一般不用,大致就是错误重传是在检测到应答机制非正常或者数据传输非正常时候,使用IIC控制器和软件来重复传输数据(设置最大重复传输次数。)硬件检测就是检测时钟线和数据线的高低电平变化,来确定传输错误原因。

I2C设备规格:

熟悉要使用的具体I2C设备的规格说明、数据手册或参考资料。
学习设备的功能和特性,包括寄存器、命令、数据格式等。

主机读取数据

在这里插入图片描述

IIC通信过程

  1. 主机发送起始条件(占用总线)——在 SCL 为高电平时,SDA 产生一个下降沿
  2. 主机发送器件地址(寻找从机)
  3. 在当前总线上的从机会将此器件地址跟自己对比,匹配成功就会回一个应答给主机。其他从机继续休眠。
  4. 主机和从机就可以建立通信,在这个过程中,接收方每成功接收到一个字节数据必须要给发送方一个应 答,如果发送方等不到应答则标志通信失败。
  5. 主机发送停止条件(释放总线)——在 SCL 高电平期间,SDA 产生一个上升沿
    MSB:高位
    LSB:低位
    数据位传输是高位在前
    在这里插入图片描述
    在这里插入图片描述

实际编程和应用:

初始化I2C接口、配置通信参数、发送和接收数据。参考代码:

void IIC1_Pin_Init(void)
{
	//PB6----SCL---推挽输出
  //PB7----SDA---开漏输出
	RCC->AHB1ENR |=0x01<<1;//端口时钟使能
	
	GPIOB->MODER &=~(0x0f<<12);
	GPIOB->MODER |=(0x05<<12);
	
	GPIOB->OTYPER |=(0x03<<6);//PB6PB7开漏输出

	
	//总线在空闲状态
	IIC1_SCL=1;
	IIC1_SDA_OUT=1;
}

/*
****************************************************************************************
* Function: IIC1_Start
* Description: 起始条件
****************************************************************************************
*/
void IIC1_Start(void)
{
	IIC1_SCL=0;
	Delay_us(6);
	IIC1_SDA_OUT=1;
	
	IIC1_SCL=1;
	Delay_us(6);//延时---起始条件的建立时间
	IIC1_SDA_OUT=0;//---产生起始条件
	Delay_us(6);//延时---起始条件的保持时间
	IIC1_SCL=0; //---结束起始条件
}

/*
****************************************************************************************
* Function: IIC1_Stop
* Description: 停止条件
****************************************************************************************
*/
void IIC1_Stop(void)
{
	IIC1_SDA_OUT=0;
	IIC1_SCL=1;
	Delay_us(6);//延时---停止条件的建立时间
	IIC1_SDA_OUT=1; //---产生了停止条件
	Delay_us(6);//延时---本次通信结束到下次通信开始的时间

}

/*
****************************************************************************************
* Function: IIC1_Send_Ack
* Description: 主机发送应答信号
* Input: ack--0表示有应答  1表示非应答
****************************************************************************************
*/
void IIC1_Send_Ack(uint8_t ack)
{

	IIC1_SCL=0;
	if(ack)//(主机准备数据)
		IIC1_SDA_OUT=1;
	else
		IIC1_SDA_OUT=0;
	Delay_us(6);//延时(数据稳定在数据线上)
	IIC1_SCL=1;//(从机在时钟线上升沿从SDA上采集数据)
	Delay_us(6);//延时(给时间从机读取数据)
	
//	IIC1_SCL=0;//方便后续的操作;防止意外产生了停止条件
}

/*
****************************************************************************************
* Function: IIC1_Revice_Ack
* Description: 主机读取应答信号
* Return: 0--有应答  1--非应答
****************************************************************************************
*/
uint8_t IIC1_Revice_Ack(void)
{
	uint8_t ack=0;
	

	IIC1_SCL=0;//(从机准备数据)
	IIC1_SDA_OUT=1;//读模式-----让输出电路与管脚断开!!!!!!!!!!
	Delay_us(6);//延时(给时间从机准备数据并且数据稳定在数据线上)
	IIC1_SCL=1;
	Delay_us(6);//延时 (给时间主机读取数据)
	if(IIC1_SDA_IN)//主机读取SDA线上的数据
		ack=1;
	
	//IIC1_SCL=0;//方便后续的操作;防止意外产生了停止条件
	
	return ack;
}

/*
****************************************************************************************
* Function: IIC1_Send_Byte
* Description: 主机发送一个字节给从机并且读取一次应答信号
* Input: 待发送的一个字节数据
* Return: 应答信号 0--有应答  1--非应答
****************************************************************************************
*/
uint8_t IIC1_Send_Byte(uint8_t data)
{
	uint8_t i=0;

	
	for(i=0;i<8;i++)
	{
		IIC1_SCL=0;
		if((data<<i)&0x80)//(主机准备数据)  
			IIC1_SDA_OUT=1;              
		else
			IIC1_SDA_OUT=0;
		Delay_us(6);//延时(数据稳定在数据线上)
		IIC1_SCL=1;//(从机在时钟线上升沿从SDA上采集数据)
		Delay_us(6);//延时(给时间从机读取数据)
	}
	//IIC1_SCL=0;//方便后续的操作;防止意外产生了停止条件
	
	return IIC1_Revice_Ack( );
}

/*
****************************************************************************************
* Function: IIC1_Revice_Byte
* Description: 主机读取一个字节并且发送一次应答信号
* Input: 应答信号 0--有应答  1--非应答
* Return: 读取的一个字节数据
****************************************************************************************
*/
uint8_t IIC1_Revice_Byte(uint8_t ack)
{
	uint8_t i=0;
	uint8_t data=0;
	
	for(i=0;i<8;i++)
	{
		IIC1_SCL=0;//(从机准备数据)
		IIC1_SDA_OUT=1;//读模式-----让输出电路与管脚断开!!!!!!!!!!
		Delay_us(6);//延时(给时间从机准备数据并且数据稳定在数据线上)
		IIC1_SCL=1;
		data = (data<<1) | (IIC1_SDA_IN);
		Delay_us(6);//延时 (给时间主机读取数据)
		
	}
	//IIC1_SCL=0;//方便后续的操作;防止意外产生了停止条件
	
	IIC1_Send_Ack(ack);
	
	return data;
}

IO 口模拟 IIC 总线

由于 IIC 控制器存在缺陷,一般都不会采用芯片内部的 IIC 控制器。所以要想采用 IIC 通信跟外设进行数据交流,就需要用 IO 口模拟 IIC 时序。IIC 总线是两线制通信协议,所以只需要采用两个 IO 口即可,一个 IO 口作为 SCL,另一个作为 SDA
IO 口初始化
作为 SCL 的 IO 口:SCL 只能由主机发出,把这个 IO 配置成输出模式,推挽输出和开漏输出均可作为 SDA 的 IO 口:SDA 是双向数据线,既能从主机发出数据,主机也能在 SDA 读取数据。刚好在 IO 口配置成输出模式时,输入电路并没有被关闭。但是,在采用输入的时候,不能让输出电路影响到输入电路,必须配置成开漏输出,在读取数据前,输出“1”把输出电路从 IO 口断开。

常见的I2C通信错误类型和故障排除方法

通信错误:包括从机设备无应答、从机设备应答错误、数据丢失或损坏等。
故障排除方法:
确保从机设备的地址正确,并确保从机设备已正确连接到I2C总线。
检查从机设备的电源供应和信号线连接是否正常。
检查主机设备的I2C控制器配置和软件实现是否正确。
考虑增加适当的延时或超时设置,以确保从机设备有足够的时间响应。

冲突和仲裁错误:当多个设备尝试在同一时间发送数据时,可能发生冲突和仲裁错误。
故障排除方法:
检查每个设备的唯一地址分配,确保每个设备具有不同的地址。
检查I2C总线上的电源供应和信号线连接是否正常。
检查设备的I2C控制器和软件实现是否正确配置。
考虑延长仲裁超时时间或增加重试机制来处理冲突。

电源供应问题:不足的电源供应可能导致通信错误或设备无法正常工作。
故障排除方法:
检查从机设备和主机设备的电源供应是否符合规格要求。
检查电源线路和电源连接是否可靠,避免电源波动或噪声干扰。
确保电源线路的容量能满足所有设备的需求,特别是在连接多个设备时。

信号线干扰和噪声:外部干扰或电磁噪声可能干扰I2C信号线的传输。
故障排除方法:
尽量减少I2C信号线与高电流、高频率或噪声源的接近。
使用屏蔽电缆或屏蔽导线来提供更好的信号干扰抑制能力。
考虑使用信号线滤波器或电磁兼容性(EMC)组件来抑制噪声。

时钟频率设置错误:不正确的时钟频率设置可能导致通信错误或设备无法同步。
故障排除方法:
检查主机设备的I2C控制器配置,确保时钟频率设置正确。
确保主机设备和从机设备之间的时钟频率匹配。
考虑降低时钟频率以提高稳定性,尤其是在长电缆或高噪声环境中。

使用IIC通信常见外设

  1. 温度传感器:I2C通信常用于连接温度传感器,例如LM75、TMP102和BMP180。这些传感器可以测量环境温度并向主机设备提供温度数据。
  2. 湿度传感器:一些湿度传感器,如SHT21和HTU21D,也可以通过I2C进行通信。它们能够测量环境的湿度并提供湿度数据。
  3. 光照传感器:TSL2561和BH1750等光照传感器通常使用I2C进行通信。它们可以测量环境的光照强度,并向主机设备提供相关数据。
  4. 三轴加速度计:常见的三轴加速度计模块(如ADXL345和MPU6050)通常通过I2C与主机设备连接。它们可以提供物体在三个轴上的加速度数据。
  5. 电子罗盘:一些电子罗盘模块(如HMC5883L和QMC5883L)也使用I2C进行通信。它们可以测量磁场,并提供与方向和导航相关的数
  6. OLED显示屏:OLED显示屏通常使用I2C总线连接到主机设备,以显示文本、图形和图像。常见的OLED控制器芯片有SSD1306和SH1106。
  7. EEPROM存储器:I2C EEPROM(Electrically Erasable Programmable Read-Only Memory)是一种非易失性存储器,可以通过I2C进行读写操作。常见的芯片有24C系列和AT24C系列。

深入学习高级特性:

学习更高级的I2C特性,如主从通信、多主通信、时钟拉伸等。
探索更复杂的应用场景,如I2C总线扩展、I2C多路复用等。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32——一文完全读懂IIC通信 的相关文章

  • 2019-07-11T09:15:41.000+0000类似时间转换

    let a 2019 07 11T09 15 41 000 0000 new Date a
  • (个人)AR电子书系统创新实训第一周(2)

    了解ZXing Net 想要在unity上实现下载资源的功能 我首先需要确认二维码扫描系统在unity上的可行性 如果要自行开发一套二维码扫描系统 不仅需要知道二维码生成和解码的原理 而且应该还需要用到一些图形学相关的代码库 如opencv
  • Android中为layout创建子文件夹

    在开发Android项目的时候 往往都有一大批java文件和layout文件 java文件分类比较简单 直接方法创建文件夹就行 但layout还需要多一步配置 看最后的文件结构图 实现步骤 1 创建相应的文件夹结构 需要注意的是 无论如何
  • ‘float‘ object has no attribute ‘decode‘

    错误代码 weibo df pd read csv Users dl Desktop 情感分析论文 词云图 微博文本数据 原始数据 原数据 表格 微博文本内容 csv print weibo df head 在读取csv或者excel文件时

随机推荐

  • Python基础—文件操作

    Python基础 文件操作 文件操作 文件是指为了重复使用或长期使用的目的 以文本或二进制形式存放于外部存储器 硬盘 U盘 光盘等 中的数据保存形式 文件是信息交换的重要途径 也是利用程序解决实际问题的重要媒介 程序对数据读取和处理都是在内
  • 单片机裸机环境下编写AT指令程序

    1 写在前面 AT指令在各种WIFI模块 2G 4G模块以及一些无线通讯模块中应用广泛 但是用过的朋友都知道 这种方式对于单片机编程来说 并不友好 本篇文章将以ESP8266 WIFI模块为例介绍在单片机裸机环境下编写AT指令程序的一种方式
  • 高精地图在无人驾驶中的应用

    转自 http 36kr com p 5060994 html 编者按 本文来自 程序员 作者 陈辰 刘少山 36氪经授权发布 高精地图是无人驾驶核心技术之一 精准的地图对无人车定位 导航与控制 以及安全至关重要 本文是 无人驾驶技术系列
  • PHP操作Redis LIST ,SET, HASH 的相关命令 (一)

    博客搬家 请访问 PHP操作Redis LIST SET HASH 的相关命令 一 PHP操作Redis KEY String 的相关命令 二 PHP操作Redis 有序集 Sorted Set 的相关命令 三
  • HttpServletRequest.getServletContext()一直提示找不到,而引出的问题

    开发j2ee项目的时候 需要用到servlet api 如果使用了maven web项目可以在pom xml中手动加入所需jar包 达到与依赖j2ee libarary同样的功能 可问题来了 1 问题描述 最近使用myeclipse10 7
  • 2023华为OD机试真题【打印机队列/排序】

    题目内容 有5台打印机打印文件 每台打印机有自己的待打印队列 因为打印的文件内容有轻重缓急之分 所以队列中的文件有1 10不同的代先级 其中数字越大优先级越高 打印机会从自己的待打印队列中选择优先级最高的文件来打印 如果存在两个优先级一样的
  • Struts框架(一)——简介

    引言 Struts 一个web应框架 概述 Struts基于MVC的一个web开源框架 也是一个表示层的框架 只能用于Web项目 内容 一 优缺点 1 优点 1 这是一个开源框架 能让开发人员更深入的了解其内部实现机制和原理 2 框架自带的
  • Spring之AOP的实现

    文章目录 什么是AOP jdk动态代理实现AOP spring实现AOP 什么是AOP AOP Aspect Oriented Programming 意为面向切面编程 我们所熟悉的是面向对象编程 OOP 将程序中所有参与模块都抽象成对象
  • vue2、3复习02-组件的生命周期,父子组件、兄弟组件、后代之间组件的数据共享,vuex,全局配置axious,使用ref引用dom元素,使用ref引用组件的方法,this.$nextTick

    1 组件的运行过程 声明周期函数 略 2 父子组件中的数据共享 父向子共享数据 子向父共享数据 父子之间双向数据同步 1 父组件向子组件共享数据 父组件通过v bind属性想子组件共享数据 子组件使用props接收数据 2 子组件向父组件共
  • 【C++】字体文件解析(FreeType)

    目录 字体文件解析 一 前言 二 基本排版概念 1 字体文件 2 字符图像和字符表 3 字符和字体指标 三 字形轮廓 四 字形指标 1 基线 笔和布局 2 排版指标和边界框 3 方位与步进 4 网格拟合的效果 5 文本宽度与边界框 五 代码
  • ipad怎么修改服务器,ipad怎么设置ipv6网络

    ipad怎么设置ipv6网络 内容精选 换一换 本文将为您介绍如何快速搭建IPv4网段或IPv6网段的VPC 以及搭建前的准备工作 IPv4 创建VPC及子网时 默认创建的网段为IPv4类型 IPv4网络无法访问Internet上的IPv6
  • 计算机组成原理实验四 微程序控制器实验报告

    我班算是几乎最后一个做实验的班级了 报告参考了一些朋友提供的数据加上一些自己的主观拙见 本人水平有限加之制作仓促难免有错误 望大家批评指正 4 1 微程序控制器实验 一 实验目的 1 掌握微程序控制器的组成原理 2 掌握微程序的编制 写入
  • 关于安装MinGw的问题

    前段时间电脑很卡 重装了系统 换了两条内存 电脑瞬间满血复活 不过重装各种东西就很麻烦了 安装个MinGW搞了我半天 所以今天记录一下怎么安装MinGW 1 哪下 MinGW w64GCC for Windows 64 32 bitshtt
  • Linux下配置java环境版本opencv

    安装gcc等编译环境 yum install gcc yum install python3 8 yum install cmake yum groupinstall Development Tools 去官方网站下载使用的压缩包4 5 0
  • nerf训练自己的数据,过程记录十分详细

    之前跑很多项目没有记录 后来再弄就不行了 这次特别记录一下 在梳理流程的同时希望给大家带来小小的帮助 我自己是在cuda11 2 windows环境下成功的 过程十分详细 有需要的朋友耐心看完 有问题可以评论区交流 首先 本文nerf是基于
  • Ubuntu 查看系统资源占用(CPU、内存、网络)

    系统监视器 CPU 内存 网络图 仅限当前桌面登录用户 gnome system monitor 查看内存占用 free h w 主要参数 b k m 分别以字节 KB MB 为单位显示内存使用情况 h 以合适的单位显示内存使用情况 最大为
  • SpringBoot+easypoi+vue导出word文档

    因为项目需求需要 临时写的有什么错误的地方望各位见谅 可以借鉴参考 easypoi依赖包
  • 在 Kylin 中实现异常值检测 UD(A)F

    本文讲解了时间序列数据异常值检测的基本概念和在 Kylin 中开发使用异常值检测 UDF 的方法 可以作为其他 UDF 开发的参考 通过在 Kylin 中移植 Hivemall 的 UDF 我们可以充分利用 Kylin 的优势 减少直接使用
  • TrafficMonitor安装报错

    由于找不到VCRUNTIME140 dll 无法继续执行代码 重新安装程序可能会解决次问题 解决方法 安装完 Visual Studio 2019后 就可以安装上了
  • STM32——一文完全读懂IIC通信

    文章目录 I2C基本概念 硬件线路 通信结构 I2C设备地址 I2C数据传输 I2C时钟速度和通信速度 I2C应答机制 I2C设备之间的冲突检测 I2C设备规格 主机读取数据 IIC通信过程 实际编程和应用 IO 口模拟 IIC 总线 常见