利用Linux的I2C子系统和i2c-tools工具集写出的对I2C设备AP3216C读写的应用程序

前言

由于NXP官方提供的BSP里已经包含了其片上I2C控制器的驱动并接入到了Linux的I2C子系统,所以我们可以直接去写与I2C有关的应用程序了。
在本篇博文中我们用两种方式对I2C设备AP3216C进行读写操作。

第一种:直接利用Linux的I2C子系统对I2C设备AP3216C进行读写操作。

第二种:利用i2c-tools工具集对I2C设备AP3216C进行读写操作,当然i2c-tools也是运行于Linux的I2C子系统基础上的用户空间工具集,之前已经介绍过它了,并且之前已经用它的命令行对I2C设备AP3216C进行过读写操作了,详情见: https://blog.youkuaiyun.com/wenhao_ir/article/details/146319007

在阅读本文前建议还是先将博文 https://blog.youkuaiyun.com/wenhao_ir/article/details/146319007 阅读一遍。

直接利用Linux的I2C子系统对I2C设备AP3216C进行读写操作

完整代码(I2C_direct_control_ATP2126C.c)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <errno.h>

#define I2C_BUS "/dev/i2c-0"  // I2C 设备文件
#define I2C_ADDR 0x1E  // AP3216C 设备地址

// 写入 I2C 设备寄存器
void i2c_write(int fd, unsigned char reg, unsigned char value) {
    unsigned char buf[2] = {reg, value};
    if (write(fd, buf, 2) != 2) {
        perror("Failed to write to I2C device");
        exit(EXIT_FAILURE);
    }
}

// 读取 I2C 设备寄存器(16位数据)
int i2c_read_word(int fd, unsigned char reg) {
    unsigned char buf[2];
    if (write(fd, &reg, 1) != 1) {
        perror("Failed to set register address");
        exit(EXIT_FAILURE);
    }
    if (read(fd, buf, 2) != 2) {
        perror("Failed to read from I2C device");
        exit(EXIT_FAILURE);
    }
    return buf[0] | (buf[1] << 8);  // 低字节在前,高字节在后
}

int main() {
    int fd = open(I2C_BUS, O_RDWR);
    if (fd < 0) {
        perror("Failed to open I2C bus");
        return EXIT_FAILURE;
    }
    if (ioctl(fd, I2C_SLAVE, I2C_ADDR) < 0) {
        perror("Failed to select I2C device");
        return EXIT_FAILURE;
    }

    // 1. 软复位 AP3216C
    i2c_write(fd, 0x00, 0x04);
    sleep(1);  // 等待复位完成

    // 2. 启用光感和距离检测
    i2c_write(fd, 0x00, 0x03);
    sleep(1);  // 等待设备启动

    while (1) {
        // 3. 读取光照强度数据
        int als_data = i2c_read_word(fd, 0x0C);
        printf("Ambient Light: %d\n", als_data);

        // 4. 读取距离数据
        int ps_data = i2c_read_word(fd, 0x0E);
        int distance = ((ps_data >> 8) & 0x3F) << 4 | (ps_data & 0x0F);
        printf("Proximity Distance: %d\n", distance);

        sleep(3);  // 每 3 秒读取一次
    }

    close(fd);
    return EXIT_SUCCESS;
}

代码ioctl(fd, I2C_SLAVE, I2C_ADDR)的作用

I2C_SLAVE 是一个 ioctl 命令,用于设置当前通信的 I2C 从设备地址,在同一条 I2C 总线上可以有多个设备,这个 ioctl 调用用于选择当前要操作的I2C设备,它告诉 Linux的I2C 驱动,后续所有 read()write() 操作都针对 0x1E 这个 I2C 设备。

代码int distance = ((ps_data >> 8) & 0x3F) << 4 | (ps_data & 0x0F);

通过博文 https://blog.youkuaiyun.com/wenhao_ir/article/details/146319007 【搜索“读取距离值”】中我们知道需要取一个字的高8位的低6位和低8位的低4位组成一个10位的数值,所以有了这个distance的计算公式。
注意:0x3F = 0b0011 1111,作与操作后就可以得到ps_data高8位的低6位。

交叉编译代码

将文件I2C_direct_control_ATP2126C.c复制到Ubuntu中:
在这里插入图片描述
运行下面的命令编译它得到ELF可执行程序:

arm-buildroot-linux-gnueabihf-gcc -o I2C_direct_control_ATP2126C I2C_direct_control_ATP2126C.c

在这里插入图片描述

测试生成的可执行程序

将刚才交叉编译生成的ELF可执行程序复制到NFS网络文件目录中:
在这里插入图片描述
打开串口终端→打开开发板→挂载网络文件系统:

mount -t nfs -o nolock,vers=3 192.168.5.11:/home/book/nfs_rootfs /mnt

然后运行下面的命令执行程序:

cd /mnt/IC2_app1
./I2C_direct_control_ATP2126C

运行结果如下:
在这里插入图片描述
然后我用手电筒照向芯片AP3216C,运行结果如下:
在这里插入图片描述
可见光照强度的数值变大了很多。

接下来我再用我的手指靠近芯片AP3216C,运行结果如下:
在这里插入图片描述
可见距离接近值也变大了很多,说明程序没有问题,测试成功。

附代码文件和编译好的ELF可执行程序

https://pan.baidu.com/s/1URp5fmx5iBuusK2GZXCKaA?pwd=3yuq

利用i2c-tools工具集对I2C设备AP3216C进行读写操作

完整代码(I2C_tools_control_ATP2126C.c)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <smbus.h>

#define I2C_BUS "/dev/i2c-0"  // I2C 设备文件
#define I2C_ADDR 0x1E  // AP3216C 设备地址

// 写入 I2C 设备寄存器
void i2c_write(int fd, unsigned char reg, unsigned char value) {
    if (i2c_smbus_write_byte_data(fd, reg, value) < 0) {
        perror("Failed to write to I2C device");
        exit(EXIT_FAILURE);
    }
}

// 读取 I2C 设备寄存器(16位数据)
int i2c_read_word(int fd, unsigned char reg) {
    int res = i2c_smbus_read_word_data(fd, reg);
    if (res < 0) {
        perror("Failed to read from I2C device");
        exit(EXIT_FAILURE);
    }
    return res; // 低字节在前,高字节在后
}

int main() {
    int fd = open(I2C_BUS, O_RDWR);
    if (fd < 0) {
        perror("Failed to open I2C bus");
        return EXIT_FAILURE;
    }
    if (ioctl(fd, I2C_SLAVE, I2C_ADDR) < 0) {
        perror("Failed to select I2C device");
        return EXIT_FAILURE;
    }

    // 1. 软复位 AP3216C
    i2c_write(fd, 0x00, 0x04);
    sleep(1);  // 等待复位完成

    // 2. 启用光感和距离检测
    i2c_write(fd, 0x00, 0x03);
    sleep(1);  // 等待设备启动

    while (1) {
        // 3. 读取光照强度数据
        int als_data = i2c_read_word(fd, 0x0C);
        printf("Ambient Light: %d\n", als_data);

        // 4. 读取距离数据
        int ps_data = i2c_read_word(fd, 0x0E);
        int distance = ((ps_data >> 8) & 0x3F) << 4 | (ps_data & 0x0F);
        printf("Proximity Distance: %d\n", distance);

        sleep(3);  // 每 3 秒读取一次
    }

    close(fd);
    return EXIT_SUCCESS;
}

代码分析说明

代码没啥好分析与详解的,与上一个代码差不多,差别就是把对设备的读写函数read、write换成了i2c-tools工具集的函数i2c_smbus_read_word_datai2c_smbus_write_byte_data,其实i2c-tools工具集的函数也是在基本的读写函数read、write上套壳开发的嘛。

交叉编译代码

首先请参考博文 https://blog.youkuaiyun.com/wenhao_ir/article/details/146364042i2c-tools编译并安装配置好。

然后把源代码文件I2C_tools_control_ATP2126C.c复制到Ubuntu中:
在这里插入图片描述
运行下面的命令编译它得到ELF可执行程序:

arm-buildroot-linux-gnueabihf-gcc -o I2C_tools_control_ATP2126C I2C_tools_control_ATP2126C.c  -L/home/book/mybuild/i2c-tools-4.2/tmp/usr/local/lib -li2c

在这里插入图片描述

测试生成的可执行程序

将刚才交叉编译生成的ELF可执行程序复制到NFS网络文件目录中:
在这里插入图片描述

打开串口终端→打开开发板→挂载网络文件系统:

mount -t nfs -o nolock,vers=3 192.168.5.11:/home/book/nfs_rootfs /mnt

然后运行下面的命令执行程序:

cd /mnt/IC2_app2
./I2C_tools_control_ATP2126C

运行结果如下:
在这里插入图片描述
然后我用手电筒照向芯片AP3216C,运行结果如下:
在这里插入图片描述
可见光照强度的数值变大了很多。

接下来我再用我的手指靠近芯片AP3216C,运行结果如下:

可见距离接近值也变大了很多,说明程序没有问题,测试成功。

在这里插入图片描述

附代码文件和编译好的ELF可执行程序

https://pan.baidu.com/s/1H6n1CtONgR8JPpqciKq6ww?pwd=z4us

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值