文章目录
i2c讲解以及zyqn中的使用
什么是i2c
https://blog.csdn.net/qq_39829913/article/details/104718185
这个i2c讲的非常好
它是电平触发采集的,不是边沿,时钟为0的时候,数据可以发生变化,的一种同步通信,IIC使用两根信号线进行通信:一根时钟线SCL,一根数据线SDA。IIC将SCL处于高时SDA拉低的动作作为开始信号,SCL处于高时SDA拉高的动作作为结束信号;传输数据时,SDA在SCL低电平时改变数据,在SCL高电平时保持数据,每个SCL脉冲的高电平传递1位数据。
工作时序:
- 数据有效性
在scl为高的时候,sda才有效 - 开始和结束
开始:在scl为高的时候,sda从高变低
结束:在scl为高的时候,sda从低变高 - 重复开始信号
重复开始信号(ReSTART/Sr): 在结束时不给出STOP信号,而以一个时钟周期内再次给出开始信号作为替代 - 字节格式
SDA数据线上的每个字节必须是8位,对于每次传输的字节数没有限制。每个字节(8位)数据传送完后紧跟着应答信号(ACK,第9位)。数据的先后顺序为:高位在前 。 - 应答信号
协议规定数据传输过程必须包含应答(ACK)。接收器通过应答告知发送的字节已被成功接收,之后发送器可以进行下一个字节的传输。主机产生数据传输过程中的所有时钟,包括用于应答的第9个时钟。发送器在应答时钟周期内释放对SDA总线的控制,这样接收器可以通过将SDA线拉低告知发送器:数据已被成功接收。
应答信号分为两种:
1)当第9位(应答位)为 低电平 时,为 ACK (Acknowledge) 信号
2)当第9位(应答位)为 高电平 时,为 NACK(Not Acknowledge)信号
主机发送数据,从机接收时,ACK信号由从机发出。当在SCL第9位时钟高电平信号期间,如果SDA仍然保持高电平,则主机可以直接产生STOP条件终止以后的传输或者继续ReSTART开始一个新的传输
从机发送数据,主机读取数据时,ACK信号由主机给出。主机响应ACK表示还需要再接收数据,而当主机接收完想要的数据后,通过发送NACK告诉从机读取数据结束、释放总线。随后主机发送STOP命令,将总线释放,结束读操作。
总线速度
为什么双向最高位3.4Mbps?
-
电气特性: I2C总线使用开漏(open-drain)或开集(open-collector)方式驱动,需要通过上拉电阻来提供高电平。这种设计使得数据线可以被任何一个设备拉低,以实现多主机控制。然而,这也意味着信号边沿的上升时间受到了限制,特别是在总线负载较重(许多设备连接到总线上)或总线电容较大的情况下。较慢的上升时间限制了最高传输速度。
-
时序和容错: 为了确保通信的可靠性,I2C协议定义了一系列时序要求,包括起始条件、停止条件、数据有效性等。这些时序要求确保了数据的完整性和设备之间的同步,但也对传输速率造成了限制。此外,协议还必须容纳一定的电气噪声和信号退化,这意味着必须有足够的时序余量来应对这些问题。
-
标准和模式: I2C协议定义了几种不同的速率模式,包括标准模式(最高100kbps)、快速模式(最高400kbps)、快速模式加(Fast Mode Plus,最高1Mbps)和高速模式(High Speed Mode,最高3.4Mbps)。每种模式都有其电气特性和时序要求,以适应不同的应用场景和性能需求。3.4Mbps的限制是高速模式下的最大速率,是通过改进驱动能力和时序控制来实现的。
-
兼容性和通用性: I2C总线的设计考虑了广泛的兼容性和通用性,以支持各种不同性能级别的设备共存。这意味着总线协议和电气特性必须在保持低成本和简单设计的同时,提供足够的通信速度。过高的速度可能会增加设计的复杂性和成本,同时减少与低速设备的兼容性。
IIC的IO有什么特点
https://blog.csdn.net/jiangdf/article/details/72779046
IIC总线上所有器件的SDA、SCL引脚输出驱动都为 开漏(OD) 结构,通过外接上拉电阻实现总线上所有节点SDA、SCL信号的线与逻辑关系。
oc门和od门
oc门与od门的基础知识
https://zhuanlan.zhihu.com/p/555471581
这个视频讲的挺好
https://www.bilibili.com/video/BV1EJ411T76A/?spm_id_from=333.337.search-card.all.click&vd_source=4a58493d16f50229c3283d2be2c272ba
oc门和od门的功能
推挽电路
推挽输出两个管子始终处在一个导通另一个截止的状态。
但是推挽不能实现线与功能。
开漏od和开集oc
开漏和开集差不多,一个是cmos管,一个是三极管,现在就以三极管的oc来说,具体看知乎连接
因为 OC/OD 门电路不具备输出高电平的能力,所以在一般应用中,是需要外接上拉电阻的。 接上上拉电阻之后,输出是1就是三极管截止,输出是0就是三极管导通接地,不同的带上拉电阻的oc门都可以输出端相连,实现线与功能
i2c访问温度传感器芯片SI7021
已经是硬核的i2c,arm直接调用函数即可
首先初始化i2c
int InitialIic(XIicPs *iic, XIicPs_Config *config)
{
int Status;
//查找外设设备的配置结构体;
config = XIicPs_LookupConfig(IIC_DEVICE_ID);
//判断指针是否为空
if (NULL == config) {
return XST_FAILURE;
}
//通过配置结构体进行初始化外设;
Status = XIicPs_CfgInitialize(iic, config, config-> BaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
//设置 IIC速率;
Status = XIicPs_SetSClk(iic, IIC_SCLK_RATE);//这里设置的是100k
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
return XST_SUCCESS;
}
温度湿度寄存器的读操作
读寄存器时序(分两个步骤),
- 通过写命令设置准备读的寄存器地址,i2c读之前要先写设备id+写命令、温湿度寄存器地址,
这里用封装好的函数来
status = XIicPs_MasterSendPolled(iic, &HumCmd,ByteCount_part1,IIC_SLAVE_ADDR);//IIC_SLAVE_ADDR为设备id,HumCmd为寄存器地址,ByteCount_part1是要写入的字节数(因为寄存器地址为1个字节所以设置为1)
if (status != XST_SUCCESS) {
return XST_FAILURE;
}
- 然后再启动读数据,7个设备id+1个读命令
这里用封装好的函数来
status = XIicPs_MasterRecvPolled(iic, Hdata, ByteCount_part2, IIC_SLAVE_ADDR);//ByteCount_part2为2,因为要读2个字节出来,IIC_SLAVE_ADDR还要给进去,但寄存器地址不给了,满足i2c时序
if (status != XST_SUCCESS) {
return XST_FAILURE;
}