概述
I2C总线是由Philips公司开发的一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息。
主器件用于启动总线传送数据,并产生时钟以开放传送的器件,此时任何被寻址的器件均被认为是从器件.在总线上主和从、发和收的关系不是恒定的,而取决于此时数据传送方向。如果主机要发送数据给从器件,则主机首先寻址从器件,然后主动发送数据至从器件,最后由主机终止数据传送;如果主机要接收从器件的数据,首先由主器件寻址从器件.然后主机接收从器件发送的数据,最后由主机终止接收过程。在这种情况下.主机负责产生定时时钟和终止数据传送。
主/从配置
由于I2C协议是半双工的不能同时发送数据和同时读数据
所以设定为了半双工工作的模式。
像cpu的i2c一般都会提供外部信号,在复位后将设备配置为主模式或从模式。当这个信号被绑定到GND时,它在复位后将设备配置为临时主模式。如果左侧浮动,复位后会将设备配置为从模式。如果不连接GND,MM_N信号默认为高。
特点:
-
交换数据量少
-
数据传输率低
-
标准传输率为100KHZ、快速模式400KHZ的时钟
原理图:
相应的I2C采集芯片的描述:
测试环境:linux
测试:
#include <stdio.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <unistd.h>
#define I2C_BUS_FILE "/dev/i2c-1"
#define I2C_DEVICE_ADDR_1 0x44
#define I2C_DEVICE_ADDR_2 0x45
int main() {
int i2c_fd;
unsigned char reg_addrs[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0xFE, 0xFF};
unsigned short reg_values_dev1[10];
unsigned short reg_values_dev2[10];
unsigned char data_2[3]={0x05,0xa,0x00};
// 打开I2C总线设备文件
i2c_fd = open(I2C_BUS_FILE, O_RDWR);
if (i2c_fd < 0) {
perror("Failed to open I2C bus");
return 1;
}
if (ioctl(i2c_fd, I2C_SLAVE, I2C_DEVICE_ADDR_1) < 0) {
perror("Failed to set I2C address for device 1");
close(i2c_fd);
return 1;
}
if (write(i2c_fd, data_2, 3) != 3) {
perror("Failed to write data");
close(i2c_fd);
return 1;
}
for (int i = 0; i < 10; i++) {
unsigned char reg_addr = reg_addrs[i];
unsigned char data[2];
if (write(i2c_fd, ®_addr, 1) != 1) {
perror("Failed to write register address for device 1");
close(i2c_fd);
return 1;
}
if (read(i2c_fd, &data, 2) != 2) {
perror("Failed to read from I2C for device 1");
close(i2c_fd);
return 1;
}
reg_values_dev1[i] = (data[0] << 8) | data[1];
}
if (ioctl(i2c_fd, I2C_SLAVE, I2C_DEVICE_ADDR_2) < 0) {
perror("Failed to set I2C address for device 2");
close(i2c_fd);
return 1;
}
if (write(i2c_fd, data_2, 3) != 3) {
perror("Failed to write data");
close(i2c_fd);
return 1;
}
for (int i = 0; i < 10; i++) {
unsigned char reg_addr = reg_addrs[i];
unsigned char data[2];
if (write(i2c_fd, ®_addr, 1) != 1) {
perror("Failed to write register address for device 2");
close(i2c_fd);
return 1;
}
// 读取数据
if (read(i2c_fd, &data, 2) != 2) {
perror("Failed to read from I2C for device 2");
close(i2c_fd);
return 1;
}
reg_values_dev2[i] = (data[0] << 8) | data[1];
}
close(i2c_fd);
float result0 = reg_values_dev1[1] * 2.5 / 1000;
float result1 = reg_values_dev1[2] * 1.25 / 1000;
float result2 = reg_values_dev1[4] * 1 / 1000;
float result3 = reg_values_dev1[3] * 25 / 1000;
float result4 = reg_values_dev2[1] * 2.5 / 1000;
float result5 = reg_values_dev2[2] * 1.25 / 1000;
float result6 = reg_values_dev2[4] * 1 / 1000;
float result7 = reg_values_dev2[3] * 25 / 1000;
printf("Device 1 data: 0x%X \n",I2C_DEVICE_ADDR_1);
printf("Bus Voltage Register %.3fV ,Current Register %.3fA , Power Register %.3fW \n", result1,result2,result3);
printf("Device 2 data: 0x%X\n",I2C_DEVICE_ADDR_2);
printf("Bus Voltage Register %.3fV ,Current Register %.3fA , Power Register %.3fW \n", result5,result6,result7);
return 0;
}