一、I2C简介 I2C使用两条线在主控制器和从机之间通信,SCL(串行时钟线)和SDA(串行数据线),这两条线需接5~10欧上拉电阻,总线空闲空闲时,SCL和SDA处于高电平,I2C总线标准模式速度可以达到100K/S,快速模式可以达到400K/S。 一个I2C总线可以挂多个I2C从设备,通过I2C器件地址去识别不同的设备,如图 二、I2C通信原理 1.起始位 2.停止位 3.数据传输:I2C在数据传输时要保证SCL高电平期间,SDA数据稳定,因此SDA上数据变化只能SCL低电平期间发生,如图 4.应答信号:当I2C主机发送完8位数据后,将SDA设置为输入状态,等待I2C从机应答,应答信号由从机发出,主机需要提供应答信号所需时钟,主机发送完8位数据后,紧跟一个时钟信号,就是给应答信号提供的,从机将SDA拉低来表示发出应答信号,表示通信成功,否则表示通信失败,I2C总线是单字节读写时序 5.I2C写时序
- 开始信号
- 发送 I2C 设备地址,每个 I2C 器件都有一个设备地址,通过发送具体的设备地址来决定访问哪个I2C 器件。这是一个8位的数据,其中高7位是设备地址,最后1位是读写位,为1的话表示这是一个读操作,为0的话表示这是一个写操作。
- I2C 器件地址后面跟着一个读写位,为0表示写操作,为1表示读操作。
- 从机发送的 ACK 应答信号。
- 重新发送开始信号。
- 发送要写写入数据的寄存器地址。
- 从机发送的 ACK 应答信号。
- 发送要写入寄存器的数据
- 从机发送的 ACK 应答信号。
- 停止信号。
6.I2C读时序:读时序分为4大步,第一步是发送设备地址,第二步是发送要读取的寄存器地址,第三步重新发送设备地址,最后一步就是I2C从器件输出要读取的寄存器值
- 主机发送起始信号。
- 主机发送要读取的I2C从设备地址。
- 读写控制位,因为是向I2C从设备发送数据,因此是写信号0。
- 从机发送的ACK应答信号。
- 重新发送START信号。
- 主机发送要读取的寄存器地址。
- 从机发送的ACK应答信号。
- 重新发送START信号。
- 重新发送要读取的I2C从设备地址。
- 读写控制位,这里是读信号1,表示接下来是从I2C从设备里面读取数据。
- 从机发送的ACK应答信号。
- 从 I2C 器件里面读取到的数据。
- 主机发出NO ACK信号,表示读取完成,不需要从机再发送ACK信号了。
- 主机发出STOP信号,停止I2C通信
三、代码实现I2C读写时序
#include <linux/i2c.h>
static int i2c_write(struct i2c_adapter *i2c_adap,unsigned int address,
unsigned int len, unsigned char const *data)
{
struct i2c_msg msgs[1];
int ret;
if(!data || !i2c_adap){
printk("---error---\n");
}
msgs[0].addr=address;
msgs[0].flags=0;
msgs[0].buf=(unsigned char *)data;
msgs[0].len=len;
ret=i2c_transfer(i2c_adap,msgs,1);
if (ret == 1)
return 0;
else if(ret == 0)
return -EBUSY;
else
return ret;
}
static int i2c_read(struct i2c_adapter *i2c_adap,
unsigned int address, unsigned int reg,
unsigned int len, unsigned char *data)
{
struct i2c_msg msgs[2];
int ret;
if(!data || !i2c_adap){
printk("---error---\n");
}
msgs[0].addr=address;
msgs[0].flags=0;
msgs[0].buf=®
msgs[0].len=1;
msgs[1].addr=address;
msgs[1].flags=I2C_M_RD;
msgs[1].buf=data;
msgs[1].len=len;
ret=i2c_transfer(i2c_adap,msgs,2);
if (ret == 2)
return 0;
else if(ret == 0)
return -EBUSY;
else
return ret;
}
在学习中进步,如有错误,请多多批评指正
|