imx6ull开发板i2c应用编程读取AP3216c传感器数据

简介: imx6ull开发板i2c应用编程读取AP3216c传感器数据


一.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应用编程,这个例子只是初步了解,里面涉及的函数,以及结构体还需自己去查阅资料,深入了解。以上已是全部代码(只是分开写)。最后谢谢大家阅读。

目录
相关文章
|
Ubuntu Linux 虚拟化
Linux下的IMX6ULL——构建bootloader、内核、文件系统(四)
Linux下的IMX6ULL——构建bootloader、内核、文件系统(四)
796 0
Linux下的IMX6ULL——构建bootloader、内核、文件系统(四)
|
Windows
msi文件解包
msi文件解包
2162 1
msi文件解包
|
缓存 Unix Linux
进程间通信之匿名管道和命名管道的理解和实现【Linux】
进程间通信之匿名管道和命名管道的理解和实现【Linux】
456 0
|
存储 C++ 容器
【C++】map、set基本用法
本文介绍了C++ STL中的`map`和`set`两种关联容器。`map`用于存储键值对,每个键唯一;而`set`存储唯一元素,不包含值。两者均基于红黑树实现,支持高效的查找、插入和删除操作。文中详细列举了它们的构造方法、迭代器、容量检查、元素修改等常用接口,并简要对比了`map`与`set`的主要差异。此外,还介绍了允许重复元素的`multiset`和`multimap`。
323 3
【C++】map、set基本用法
|
C++
Leetcode第一题(两数之和)
这篇文章介绍了解决LeetCode第一题“两数之和”的两种方法:暴力法和哈希表法,并提供了相应的C++代码实现。
292 0
Leetcode第一题(两数之和)
|
Linux 开发工具
You could try using --skip-broken to work around the problem You could try running: rpm -Va --nofi
linux配置环境变量操作失误出现:/usr/libexec/grepconf.sh: line 5: grep: command not found 的解决办法
497 2
|
编解码 监控 物联网
【学员源鑫笔记】韦东山物联网流媒体实战项目-智慧家居视频监控系统(值得收藏)
【学员源鑫笔记】韦东山物联网流媒体实战项目-智慧家居视频监控系统(值得收藏)
1087 0
|
传感器
【经典案例】STM32F407使用HAL库配置I2C详解
STM32F407是一个强大的微控制器,广泛应用于嵌入式系统中。在许多应用中,我们需要使用I2C总线来与传感器、EEPROM、显示屏等外设进行通信。本文将详细介绍如何使用STM32 HAL库来配置和使用I2C接口。
2352 2
|
Ubuntu 物联网 Linux
手把手移植物联网项目到arm开发板笔记(上)
手把手移植物联网项目到arm开发板笔记
735 0
|
Java 数据安全/隐私保护 Spring
SpringSecurity6从入门到实战之SpringSecurity快速入门
这篇文章是关于使用SpringSecurity 6进行快速入门的教程。首先介绍了所需的环境配置,包括SpringSecurity 6.0.8、SpringBoot 3.0.12和JDK 17。接着,通过步骤展示了如何创建一个新的SpringBoot工程,并添加Web支持。然后,运行工程并测试了Hello接口,确保其正常工作。之后,引入SpringSecurity依赖后,无需额外配置,系统即实现了基础的认证功能,自动重定向到登录页面。文章通过截图详细说明了这个过程,包括控制台日志、登录页面以及登录后的资源访问。