网站模块报价,外贸网站开发开发,上海网站建设网站开发,做网站的怎么获取客户信息全面解析 I2C 通信协议
lvy 嵌入式学习规划 2023-12-22 21:20 发表于陕西 嵌入式学习规划
嵌入式软件、C语言、ARM、Linux、内核、驱动、操作系统
80篇原创内容
公众号 点击左上方蓝色“嵌入式学习规划”#xff0c;选择“设为星标” 1、什么是I2C协议
I2C 协议是一个允许…
全面解析 I2C 通信协议
lvy 嵌入式学习规划 2023-12-22 21:20 发表于陕西 嵌入式学习规划
嵌入式软件、C语言、ARM、Linux、内核、驱动、操作系统
80篇原创内容
公众号 点击左上方蓝色“嵌入式学习规划”选择“设为星标” 1、什么是I2C协议
I2C 协议是一个允许多个 “从机” 芯片和一个或更多的 “主机” 芯片进行通讯的协议。它就像串行外设接口SPI一样只能用于短距离通信。又像异步串行接口如RS232或UART 只需要两根信号线来交换信息。
实现I2C需要两根信号线完成信息交换SCL时钟信号线SDA数据输入/输出线。它属于同步通信由于输入输出数据均使用一根线因此通信方向为半双工。
总结短距离、一主多从、半双工、两根线、同步通讯 2、名词解释
什么是半双工什么是同步通讯什么是异步通讯
2.1 什么是半双工
数据通信中数据在线路上的传送方式可以分为单工通信、半双工通信和全双工通信三种。
单工通信 是指消息只能单方向传输的工作方式。例如遥控、遥测(一部分)就是单工通信方式。单工通信信道是单向信道发送端和接收端的身份是固定的发送端只能发送信息不能接收信息接收端只能接收信息不能发送信息数据信号仅从一端传送到另一端即信息流是单方向的。
半双工 是指数据可以沿两个方向传送但同一时刻一个信道只允许单方向传送因此又被称为双向交替通信。信息在两点之间能够在两个方向上进行发送但不能同时发送的工作方式。半双工方式要求收发两端都有发送装置和接收装置。由于这种方式要频繁变换信道方向故效率低但可以节约传输线路。
全双工 是指在通信的任意时刻线路上可以同时存在A到B和B到A的双向信号传输。在全双工方式下通信系统的每一端都设置了发送器和接收器因此能控制数据同时在两个方向上传送。全双工方式无需进行方向的切换因此没有切换操作所产生的时间延迟这对那些不能有时间延误的交互式应用例如远程监测和控制系统十分有利。比如电话机则是一种全双工设备其通话双方可以同时进行对话。 2.2 什么是同步通讯
同步通信 发送端在发送串行数据的同时提供一个时钟信号并按照一定的约定例如在时钟信号的上升沿的时候将数据发送出去发送数据接收端根据发送端提供的时钟信号以及大家的约定接收数据。如I2C、SPI等有时钟信号的协议都属于这种通信方式。
异步通信 接收方并不知道数据什么时候会到达收发双方可以有各自自己的时钟。发送方发送的时间间隔可以不均接收方是在数据的起始位和停止位的帮助下实现信息同步的。这种传输通常是很小的分组比如一个字符为一组数据组配备起始位和结束位。所以这种传输方式的效率是比较低的因为额外加入了很多的辅助位作为负载常用在低速的传输中。
同步通信与异步通信区别
1同步通信要求接收端时钟频率和发送端时钟频率一致发送端发送连续的比特流异步通信时不要求接收端时钟和发送端时钟同步发送端发送完一个字节后可经过任意长的时间间隔再发送下一个字节。
2同步通信效率高异步通信效率较低。
3同步通信较复杂双方时钟的允许误差较小异步通信简单双方时钟可允许一定误差。
4同步通信可用于点对多点异步通信只适用于点对点。
3、I2C的功能特点
I2C最重要的功能包括 只需要两条总线 没有严格的波特率要求例如使用RS232主设备生成总线时钟 所有组件之间都存在简单的主/从关系连接到总线的每个设备均可通过唯一地址进行软件寻址 I²C是真正的多主设备总线可提供仲裁和冲突检测
传输速度 标准模式Standard Mode 100 Kbps 快速模式Fast Mode 400 Kbps 高速模式High speed mode 3.4 Mbps 超快速模式Ultra fast mode 5 Mbps
最大主设备数无限制
最大从机数理论上是127 4、I2C的高阻态
漏极开路Open Drain即高阻状态适用于输入/输出其可独立输入/输出低电平和高阻状态若需要产生高电平则需使用外部上拉电阻
高阻状态高阻状态是三态门电路的一种状态。逻辑门的输出除有高、低电平两种状态外还有第三种状态——高阻状态的门电路。电路分析时高阻态可做开路理解。
我们知道IIC的所有设备是接在一根总线上的那么我们进行通信的时候往往只是几个设备进行通信那么这时候其余的空闲设备可能会受到总线干扰或者干扰到总线怎么办呢
为了避免总线信号的混乱IIC 的空闲状态只能有外部上拉 而此时空闲设备被拉到了高阻态也就是相当于断路 整个IIC总线只有开启了的设备才会正常进行通信而不会干扰到其他设备。
5、数据传输协议
主设备和从设备进行数据传输时遵循以下协议格式。数据通过一条SDA数据线在主设备和从设备之间传输0和1的串行数据。串行数据序列的结构可以分为 5.1 开始位
当主设备决定开始通讯时需要发送开始信号并且执行以下过程 将SDA线由高电平切换成低电平 将SCL线由高电平切换成低电平 在主设备发送开始条件信号之后所有从机即使处于睡眠模式也将变为活动状态并等待接收地址位。 5.2 地址位
地址位支持 7bit、10bit主设备如果需要向从机发送/接收数据首先要发送对应从机的地址然后会匹配总线上挂载的从机的地址故地址为主要用来辨识不同设备。
地址位由主机发送从设备负责接受并识别该地址是否位自己地址。
5.3 读写位
由于I2C是半双工通讯所以设备需要确定数据传输的方向故引入了读写位。 如果主设备需要将数据发送到从设备则该位设置为 0 如果主设备需要往从设备接收数据则将其设置为 1
读写位由主机发送1表示读操作0表示写操作。
5.4 应答位
I2C最大的一个特点就是有完善的应答机制从机接收到主机的数据时会回复一个应答信号来通知主机表示“我收到了”。
应答信号 出现在1个字节传输完成之后即第9个SCL时钟周期内此时主机需要释放SDA总线把总线控制权交给从机由于上拉电阻的作用此时总线为高电平如果从机正确的收到了主机发来的数据会把SDA拉低表示应答响应。 非应答信号当第9个SCL时钟周期时SDA保持高电平表示非应答信号。 非应答信号可能是主机产生也可能是从机产生产生非应答信号的情况主要有以下几种 I2C总线上没有主机所指定地址的从机设备 从机正在执行一些操作处于忙状态还没有准备好与主机通讯 主机发送的一些控制命令从机不支持 主机接收从机数据时主机产生非应答信号通知从机数据传输结束不要再发数据了
5.5 数据位
I2C数据总线传输要保证在SCL为高电平时SDA数据稳定所以SDA上数据变化只能在SCL为低电平时 一次传输的数据总共有8位由发送方设置它需要将数据位传输到接收方。发送之后会紧跟一个ACK / NACK位如果接收器成功接收到数据则从机发送ACK。否则从机发送NACK。
数据可以重复发送多个直到接收到停止位为止。
5.6 停止位
当主设备决定结束通讯时需要发送结束信号需要执行以下动作 先将SDA线从低电压电平切换到高电压电平 再将SCL线从高电平拉到低电平
5.7 总结
写寄存器的标准流程为 Master发起START Master发送I2C addr7bit和w操作01bit等待ACK Slave发送ACK Master发送reg addr8bit等待ACK Slave发送ACK Master发送data8bit即要写入寄存器中的数据等待ACK Slave发送ACK 第6步和第7步可以重复多次即顺序写多个寄存器 Master发起STOP
读寄存器的标准流程为 Master发送I2C addr7bit和w操作11bit等待ACK Slave发送ACK Master发送reg addr8bit等待ACK Slave发送ACK Master发起START Master发送I2C addr7bit和r操作11bit等待ACK Slave发送ACK Slave发送data8bit即寄存器里的值 Master发送ACK 第8步和第9步可以重复多次即顺序读多个寄存器
6、仲裁机制
在多主的通信系统中。总线上有多个节点它们都有自己的寻址地址可以作为从节点被别的节点访问同时它们都可以作为主节点向其他的节点发送控制字节和传送数据。
但是如果有两个或两个以上的节点都向总线上发送启动信号并开始传送数据这样就形成了冲突。要解决这种冲突就要进行仲裁的判决这就是I2C总线上的仲裁。
I2C总线上的仲裁分两部分SCL线的同步和SDA线的仲裁。
6.1 SCL线的同步
SCL同步是由于总线具有线 “与” 的逻辑功能开漏输出即只要有一个节点发送低电平时总线上就表现为低电平。当所有的节点都发送高电平时总线才能表现为高电平。
正是由于线“与”逻辑功能的原理当多个节点同时发送时钟信号时在总线上表现的是统一的时钟信号这就是SCL的同步原理。 6.2 SDA线的仲裁
总线仲裁是为了解决多设备同时竞争中线控制权的问题通过一定的裸机来决定哪个设备能够获得最终的总线控制权。
SDA线的仲裁也是建立在总线具有线“与”逻辑功能的原理上的。节点在发送1位数据后比较总线上所呈现的数据与自己发送的是否一致类似于CAN总线的回读机制。 是继续发送 否则退出竞争
I2C总线的控制逻辑低电平优先
SDA线的仲裁可以保证I2C总线系统在多个主节点同时企图控制总线时通信正常进行并且数据不丢失总线系统通过仲裁只允许一个主节点可以继续占据总线。 上图过程分析
第一个周期所有设备发送1做与运算后的结果为1与自己发送的数据相同继续发送
第二个周期所有设备发送1做与运算后的结果为1与自己发送的数据相同继续发送
第三个周期所有设备发送0做与运算后的结果为0与自己发送的数据相同继续发送
第四个周期AB设备发送1C设备发送0做与运算后结果为0与AB发送的数据不同则AB退出竞争节点C获胜 注若AB两个设备发送0C设备发送1这最后与运算结果为0与AB数据格式相同与C数据格式不同则C退出AB继续发送直至AB中有一个退出。
SDA 仲裁 和 SCL 时钟同步处理过程没有先后关系而是同时进行的。
7、I2C死锁
在实际使用过程中I2C比较容易出现的一个问题就是死锁 死锁在I2C中主要表现为I2C死锁时表现为SCL为高SDA一直为低。
在I2C主设备进行读写操作的过程中主设备在开始信号后控制SCL产生8个时钟脉冲然后拉低SCL信号为低电平在这个时候从设备输出应答信号将SDA信号拉为低电平。
如果这个时候主设备异常复位SCL就会被释放为高电平。此时如果从设备没有复位就会继续I2C的应答将SDA一直拉为低电平直到SCL变为低电平才会结束应答信号。
而对于I2C主设备来说复位后检测SCL和SDA信号如果发现SDA信号为低电平则会认为I2C总线被占用会一直等待SCL和SDA信号变为高电平。
这样I2C主设备等待从设备释放SDA信号而同时I2C从设备又在等待主设备将SCL信号拉低以释放应答信号两者相互等待I2C总线进人一种死锁状态。
同样当I2C进行读操作I2C从设备应答后输出数据如果在这个时刻I2C主设备异常复位而此时I2C从设备输出的数据位正好为0也会导致I2C总线进入死锁状态。
8、I2C的代码实现
参考了STM32的HAL库中I2C驱动主设备发送函数HAL_I2C_Master_Transmit()具体如下
/*** brief Transmits in master mode an amount of data in blocking mode.* param hi2c Pointer to a I2C_HandleTypeDef structure that contains* the configuration information for the specified I2C.* param DevAddress Target device address: The device 7 bits address value* in datasheet must be shifted to the left before calling the interface* param pData Pointer to data buffer* param Size Amount of data to be sent* param Timeout Timeout duration* retval HAL status*/
HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout){uint32_t tickstart 0x00U;/* Init tickstart for timeout management*/tickstart HAL_GetTick();if(hi2c-State HAL_I2C_STATE_READY){/* Wait until BUSY flag is reset */if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart) ! HAL_OK){return HAL_BUSY;}/* Process Locked */__HAL_LOCK(hi2c);/* Check if the I2C is already enabled */if((hi2c-Instance-CR1 I2C_CR1_PE) ! I2C_CR1_PE){/* Enable I2C peripheral */__HAL_I2C_ENABLE(hi2c);}/* Disable Pos */hi2c-Instance-CR1 ~I2C_CR1_POS;hi2c-State HAL_I2C_STATE_BUSY_TX;hi2c-Mode HAL_I2C_MODE_MASTER;hi2c-ErrorCode HAL_I2C_ERROR_NONE;/* Prepare transfer parameters */hi2c-pBuffPtr pData;hi2c-XferCount Size;hi2c-XferOptions I2C_NO_OPTION_FRAME;hi2c-XferSize hi2c-XferCount;/* Send Slave Address */if(I2C_MasterRequestWrite(hi2c, DevAddress, Timeout, tickstart) ! HAL_OK){if(hi2c-ErrorCode HAL_I2C_ERROR_AF){/* Process Unlocked */__HAL_UNLOCK(hi2c);return HAL_ERROR;}else{/* Process Unlocked */__HAL_UNLOCK(hi2c);return HAL_TIMEOUT;}}/* Clear ADDR flag */__HAL_I2C_CLEAR_ADDRFLAG(hi2c);while(hi2c-XferSize 0U){/* Wait until TXE flag is set */if(I2C_WaitOnTXEFlagUntilTimeout(hi2c, Timeout, tickstart) ! HAL_OK){if(hi2c-ErrorCode HAL_I2C_ERROR_AF){/* Generate Stop */hi2c-Instance-CR1 | I2C_CR1_STOP;return HAL_ERROR;}else{return HAL_TIMEOUT;}}/* Write data to DR */hi2c-Instance-DR (*hi2c-pBuffPtr);hi2c-XferCount--;hi2c-XferSize--;if((__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) SET) (hi2c-XferSize ! 0U)){/* Write data to DR */hi2c-Instance-DR (*hi2c-pBuffPtr);hi2c-XferCount--;hi2c-XferSize--;}/* Wait until BTF flag is set */if(I2C_WaitOnBTFFlagUntilTimeout(hi2c, Timeout, tickstart) ! HAL_OK){if(hi2c-ErrorCode HAL_I2C_ERROR_AF){/* Generate Stop */hi2c-Instance-CR1 | I2C_CR1_STOP;return HAL_ERROR;}else{return HAL_TIMEOUT;}}}/* Generate Stop */hi2c-Instance-CR1 | I2C_CR1_STOP;hi2c-State HAL_I2C_STATE_READY;hi2c-Mode HAL_I2C_MODE_NONE;/* Process Unlocked */__HAL_UNLOCK(hi2c);return HAL_OK;}else{return HAL_BUSY;}
}