当前位置: 首页 > news >正文

利用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.csdn.net/wenhao_ir/article/details/146319007

在阅读本文前建议还是先将博文 https://blog.csdn.net/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.csdn.net/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.csdn.net/wenhao_ir/article/details/146364042 把i2c-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

http://www.dtcms.com/a/79955.html

相关文章:

  • Python Cookbook-4.8 二维阵列变换
  • ZooKeeper集群高可用性测试与实践:从规划到故障模拟
  • 单片机flash存储也做磨损均衡
  • 分布式训练与多GPU加速策略
  • 创造型设计模式
  • IP查询底层逻辑解析:数据包与地理位置
  • 【虚幻引擎UE5】SpawnActor生成Character实例不执行AI Move To,未初始化AIController的原因和解决方法
  • 嵌入式4-Modbus
  • 网络类型及数据链路层协议【复习篇】
  • MySQL身份验证的auth_socket插件
  • 使用 `pytest` 框架时,可以通过极限封装将 YAML 文件的读取、解析
  • Kotlin v2.1.20 发布,标准库又有哪些变化?
  • 设计模式在事件处理系统中的应用
  • Qt之MVC架构MVD
  • cmake教程
  • JAVA URL和URI差异对比
  • C语言入门知识(上)
  • 搭建React简单项目
  • lua垃圾回收
  • javaAPI文档中文版(在线版)
  • 绿盟面试题
  • centos家用笔记
  • 智能汽车图像及视频处理方案,支持视频智能拍摄能力
  • ModuleNotFoundError: No module named ‘flask‘ 错误
  • Cursor/windsurf+MCP+Blender自动建模还有多远
  • JimuReport与deepseek结合,颠覆现有BI模式
  • ASFF:Learning Spatial Fusion for Single-Shot Object Detection
  • 蓝桥杯 积木画
  • llama源码学习·model.py[3]ROPE旋转位置编码(4)ROPE的应用
  • Python八字排盘系统实现分析