一.AP3216c传感器
AP3216C 是红外、光强、距离三合一的传感器。以读出光强、距离值为例。
⚫ 复位:往寄存器 0 写入 0x4
⚫ 使能:往寄存器 0 写入 0x3
⚫ 读光强:读寄存器 0xC、 0xD 得到 2 字节的光强
⚫ 读距离:读寄存器 0xE、 0xF 得到 2 字节的距离值
注意,AP3216C 的设备地址是 0x1E,假设节在 I2C BUS0 上,操作命令如下:
这里我们使用的是i2c-tools在开发板上进行测试,不知道这个工具的可以自行百度。(如果开发板未安装,需要自己安装)
⚫ 使用 SMBus 协议
i2cset -f -y 0 0x1e 0 0x4
i2cset -f -y 0 0x1e 0 0x3
i2cget -f -y 0 0x1e 0xc w
i2cget -f -y 0 0x1e 0xe w
⚫ 使用 I2C 协议
i2ctransfer -f -y 0 w2@0x1e 0 0x4
i2ctransfer -f -y 0 w2@0x1e 0 0x3
i2ctransfer -f -y 0 w1@0x1e 0xc r2
i2ctransfer -f -y 0 w1@0x1e 0xe r2
如图:读取传感器数据
SMBus协议可以这么理解是I2C的一个子集,比I2C更为严格。
二.I2C应用编程读取AP3216c传感器数据
先展示效果,如下:
2.1 初始化ap3216c
#include <stdio.h> #include <sys/ioctl.h> #include <linux/i2c.h> #include <linux/i2c-dev.h> #include <unistd.h> #include <fcntl.h> #define AP3216C_ADDR 0x1e static int fd; int ap3216c_init(void) { char buf[100]; //int err; struct i2c_rdwr_ioctl_data rdwr; struct i2c_msg msgs[1]; int nmsgs_sent; fd=open("/dev/i2c-0",O_RDWR);//打开设备,读写 if(fd<0) { printf("can not open i2c bus %d\n",I2C_BUS); return 0; } msgs[0].addr = AP3216C_ADDR; //ap3216c的地址 msgs[0].flags = 0; // 写数据:0,读数据:1 msgs[0].len = 2; //buf长度这里为2 msgs[0].buf = buf; buf[0] = 0; //第一字节为寄存器地址 buf[1] = 4; //第二字节是数据 rdwr.msgs = msgs; rdwr.nmsgs = 1;//msgs的数量 nmsgs_sent = ioctl(fd, I2C_RDWR, &rdwr); if (nmsgs_sent != 1) { printf("can not reset ap3216c\n"); return -1; /* err */ } /* enable ap3216c */ msgs[0].addr = AP3216C_ADDR; msgs[0].flags = 0; /* 写数据:0,读数据:1 */ msgs[0].len = 2; msgs[0].buf = buf; buf[0] = 0; //第一字节为寄存器地址 buf[1] = 3; //第二字节是数据 rdwr.msgs = msgs; rdwr.nmsgs = 1; nmsgs_sent = ioctl(fd, I2C_RDWR, &rdwr);//调用驱动层代码,将数据传递 if (nmsgs_sent != 1) { printf("can not enable ap3216c\n"); return -1; /* err */ } return 0; }
2.2 读取光照数据
int ap3216c_read_light(void) { struct i2c_rdwr_ioctl_data rdwr; struct i2c_msg msgs[2]; int nmsgs_sent; char buf_tx[1]; char buf_rx[2]; int light; msgs[0].addr=AP3216C_ADDR; msgs[0].flags=0;//写数据 msgs[0].len=1; msgs[0].buf=buf_tx; buf_tx[0]=0xc; //寄存器地址 msgs[1].addr = AP3216C_ADDR; msgs[1].flags = I2C_M_RD; /* 读数据:1, I2C_M_RD */ msgs[1].len = 2; //读取长度2字节 msgs[1].buf = buf_rx; rdwr.msgs = msgs; rdwr.nmsgs = 2; nmsgs_sent = ioctl(fd, I2C_RDWR, &rdwr);//调用驱动层代码 if (nmsgs_sent != 2) { printf("can not read ap3216c light\n"); return -1; /* err */ } light = (buf_rx[1]<<8) | buf_rx[0]; return light; }
2.3 读取距离值
int ap3216c_read_distance(void) { struct i2c_rdwr_ioctl_data rdwr; struct i2c_msg msgs[2]; int nmsgs_sent; char buf_tx[1]; char buf_rx[2]; int distance; /* 发送寄存器地址 */ msgs[0].addr = AP3216C_ADDR; msgs[0].flags = 0; /* 写:0*/ msgs[0].len = 1; msgs[0].buf = buf_tx; buf_tx[0] = 0xe; //寄存器地址 msgs[1].addr = AP3216C_ADDR; msgs[1].flags = I2C_M_RD; /* read:1, 读:I2C_M_RD */ msgs[1].len = 2; msgs[1].buf = buf_rx; rdwr.msgs = msgs; rdwr.nmsgs = 2; nmsgs_sent = ioctl(fd, I2C_RDWR, &rdwr); if (nmsgs_sent != 2) { printf("can not read ap3216c light\n"); return -1; /* err */ } distance = ((buf_rx[1] & 0x3F)<<4) | (buf_rx[0] & 0xf); return distance; }
2.4 主函数
int main(int argc, char **argv) { int err; int light, distance; int cnt = 0; err = ap3216c_init(); if (err) { printf("ap3216c_init err : %d\n", err); } while (1) { light = ap3216c_read_light(); distance = ap3216c_read_distance(); printf("%03d: light = %d, distance = %d\n", cnt, light, distance); cnt++; sleep(5); } return 0; }
三.总结
读取ap3216是i2c应用编程的很好例子,以此来掌握i2c应用编程,这个例子只是初步了解,里面涉及的函数,以及结构体还需自己去查阅资料,深入了解。以上已是全部代码(只是分开写)。最后谢谢大家阅读。