STM32中的I2C通信【AP3216C光传感器】

AP3216C

简介

AP3216C 是敦南科技推出的一款三合一环境传感器, 它包含了:数字环境光传感器(ALS)、接近传感器(PS)和一个红外 LED(IR)。该芯片通过 IIC 接口和 MCU 连接,并支持中断(INT)输出。AP3216C 的特点如下:

  • IIC 接口,支持高达 400KHz 通信速率
  • 支持多种工作模式(ALS、PS+IR、ALS+PS+IR 等)
  • 内置温度补偿电路
  • 工作温度支持-30~80℃
  • 环境光传感器具有 16 位分辨率
  • 接近传感器具有 10 位分辨率
  • 红外传感器具有 10 位分辨率
  • 超小封装(4.12.41.35mm)

因为以上一些特性,AP3216C 被广泛应用于智能手机上面,用来检测光强度(自动背光控制),和接近开关控制(听筒靠近耳朵,手机自动灭屏功能)。

写寄存器

AP3216C写寄存器时序
先发送 AP3216C 的地址(7 位,为0X1E,左移一位后为 0X3C),最低位 W=0 表示写数据,随后发送 8 位寄存器地址,最后发送 8 位寄存器值。其中:S,表示 IIC 起始信号;W,表示读/写标志位(W=0 表示写,W=1 表示读);A,表示应答信号;P,表示 IIC 停止信号。

读寄存器

AP3216C寄存器说明

注意:AP3216C的读取间隔至少需要大于112.5ms(一次ALS+PS+IR转换的时间)

工程

ap3216c.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "sys.h"
#include "main.h"

#ifndef __AP3216C_H
#define __AP3216C_H

#define AP3216C_ADDR 0x3C /* 原设备地址为0x1E,左移一位为0x3C*/

#endif

uint8_t ap3216c_init(void);
uint8_t ap3216c_write_one_byte(uint8_t reg, uint8_t data);
uint8_t ap3216c_read_one_byte(uint8_t reg);
void ap3216c_read_data(uint16_t *ir, uint16_t *ps, uint16_t *als);

ap3216c.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include "main.h"
#include "sys.h"
#include "ap3216c.h"
#include "custom_i2c.h"
#include "delay.h"

/**
* @brief 初始化 AP3216C
* @param 无
* @retval 返回值:0,初始化成功; 1,初始化失败
*/
uint8_t ap3216c_init(void)
{
uint8_t temp = 0;
iic_init();

ap3216c_write_one_byte(0x00, 0x04); /* 软复位AP3216C */
delay_ms(50); /* IC复位至少需要11.5ms */
ap3216c_write_one_byte(0x00, 0x03); /* ALS+PS+IR功能激活 */
temp = ap3216c_read_one_byte(0x00); /* 读取刚刚写入的0x03指令 */
if (temp == 0x03) return 0; /* IC初始化成功 */
else return 1; /* IC初始化失败 */
}

/**
* @brief AP3216C 写入一个字节
* @param reg : AP3216C目标寄存器地址
* @param data : 待写入数据
* @retval 0, 成功;
1, 失败;
*/
uint8_t ap3216c_write_one_byte(uint8_t reg, uint8_t data)
{
iic_start();

iic_send_byte(AP3216C_ADDR | 0x00); /* 发送设备地址,最低位为0,写命令 */

if (iic_wait_ack()) /* 等待应答*/
{
iic_stop(); /* 等待应答失败则直接停机 */
return 1;
}

iic_send_byte(reg); /* 发送目标寄存器地址(指针)*/
iic_wait_ack(); /* 等待应答 */
iic_send_byte(data); /* 发送待写入数据 */

if (iic_wait_ack()) /* 等待应答*/
{
iic_stop(); /* 等待应答失败则直接停机 */
return 1;
}

iic_stop();
return 0;
}

/**
* @brief AP3216C 读取一个字节
* @param reg : 待读取寄存器地址
* @retval 读到的数据
*/
uint8_t ap3216c_read_one_byte(uint8_t reg)
{
uint8_t result;

iic_start();

iic_send_byte(AP3216C_ADDR | 0x00); /* 发送设备地址,最低位为0,写命令*/
iic_wait_ack();

iic_send_byte(reg); /* 发送待读取寄存器地址 */
iic_wait_ack();

iic_start(); /* 准备开始读取,重新启动IIC以切换模式 */
iic_send_byte(AP3216C_ADDR | 0x01); /* 发送设备地址,最低位为1,读命令*/
iic_wait_ack();
result = iic_read_byte(0); /* 读取一个字节,读完后发送NACK,表示读取结束 */
iic_stop();

return result; /* 返回读取结果 */
}

/**
* @brief 读取 AP3216C 的数据
* @note 读取原始数据,包括 ALS,PS 和 IR
* 如果同时打开 ALS,IR+PS 的话两次数据读取的时间间隔要大于 112.5ms
* @param ir : IR 传感器值
* @param ps : PS 传感器值
* @param als : ALS 传感器值
* @retval 无
*/
void ap3216c_read_data(uint16_t *ir, uint16_t *ps, uint16_t *als)
{
uint8_t rx_buf[6]; /* 读取缓冲区 */
uint8_t i;

for (i = 0; i < 6; i++) /* 循环6次以读取6个寄存器的值 */
{
rx_buf[i] = ap3216c_read_one_byte(0x0A + i);
}

/* 提取IR传感器值 */
if (rx_buf[0] & 0x80) /* 判断IR第7位是否为1 */
{
*ir = 0; /* 第7位若为1则IR数据无效 */
}
else
{
/* rx_buf[1] << 2:0x0B(IR高位)数据左移2位,给低位数据留出空余*/
/* rx_buf[0] & 0x03:提取0x0A(IR低位)数据的第0位和第1位,也就是IR的最低2位*/
/* 二者进行或运算得到IR的最终值 */
*ir = ((uint16_t)rx_buf[1] << 2) | (rx_buf[0] & 0x03);
}

/* 提取ALS传感器值 */
*als = rx_buf[2] | ((uint16_t)rx_buf[3] << 8);

/* 提取PS传感器值 */
if (rx_buf[4] & 0x40) /* 判断0x0E第6位是否为1*/
{
*ps = 0; /* PS数据无效 */
}
else
{
/* (rx_buf[4] & 0x0F):取0x0E的3:0位,也就是PS的低4位 */
/* ((uint16_t)(rx_buf[5] & 0x3F) << 4):取0x0F的5:0位然后左移4位,给低4位留位置 */
/* 二者进行或运算得到PS的最终值 */
*ps = ((uint16_t)(rx_buf[5] & 0x3F) << 4) | (rx_buf[4] & 0x0F);
}
}

main.c

1
2
3
4
5
6
7
8
/* USER CODE BEGIN 2 */
while (ap3216c_init()) /* AP3216C初始化失败 */
{
uint8_t txbuf[] = "ap3216c init failed!\n";
HAL_UART_Transmit_IT(&huart1, txbuf, sizeof(txbuf));
led_red(1);
}
/* USER CODE END 2 */
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
while (1)
{
/* USER CODE END WHILE */
ap3216c_read_data(&ir, &ps, &als);

uint8_t txbuf[23];

sprintf(txbuf, "ir:%d, ps:%d, als:%d\r\n", ir, ps, als);
HAL_UART_Transmit_IT(&huart1, (uint8_t *)txbuf, sizeof(txbuf));

led_green_toggle();
delay_ms(120); /* 延时120ms以保证AP3216C采样正确 */
/* USER CODE BEGIN 3 */

}

测试

串口打印结果


STM32中的I2C通信【AP3216C光传感器】
http://akichen891.github.io/2024/12/13/STM32中的I2C通信【AP3216C光传感器】/
作者
Aki
发布于
2024年12月13日
更新于
2024年12月16日
许可协议