
最近, 一篇文章在Habr.com上闪过,其中除其他报道外,还报道了光传感器。 前一段时间,我发现并获得了一个有趣的东西-RobotDyn基于APDS-9960传感器制造的模块,该模块也知道如何测量照明水平。 在搜索并且无法在该资源上找到对此设备的引用之后,我认为这是写文章的好理由。
在本文中,我想向读者简要介绍该传感器提供的可能性,并更详细地研究如何将其用于确定颜色和测量照明水平。
APDS-9960是Avago的传感器,它是一个组合的数字传感器,具有许多有趣而有用的功能。
他知道如何识别手势,确定接近程度,并且知道如何记录环境光的强度并确定颜色。
这正是本文将要讨论的内容-在旧的STM32VLDISCOVERY和APDS-9960的帮助下,我们将测量照明并确定所有丰富的红色,绿色和蓝色阴影的颜色。
但是,在开始实际操作之前,让我首先写一些有关APDS-9960的一般功能的信息。
APDS-9960的功能图如下图所示。

手势识别
该视频很好地展示了APDS-9960上的手势识别外观的想法。
该文档描述了手势注册的原理:
为了识别手势,使用了四个定向光电二极管来记录内置LED发出的反射光(在红外范围内)。

接近检测功能
从同一文档中的描述来看,检测(近似)机制的工作原理与手势识别相同。
颜色识别和环境光水平(颜色/ ALS)
根据功能图,传感器使用适当的光电二极管确定颜色/亮度。 还指出,APDS-9960具有内置滤光片,可阻挡紫外线和红外线范围。
简化后,它看起来像这样:光电二极管记录的信号是使用ADC测量的,输入到缓冲器中,然后通过i2c发送数据。

上图中的图形摘自传感器的文档,Color Sense(RGBC)的光谱响应显示在左上方。
光电二极管的RGBC信号在由ATIME寄存器的值设置的时间段内累积。 对于SparkFun(在其“ apds9960.h”中),此值由常量DEFAULT_ATIME确定,并且等于219,对应于103毫秒。
增益可在1倍至64倍之间调节,并通过设置CONTROL AGAIN参数来确定。 常量DEFAULT_AGAIN等于1,对应于4倍增益。
实践部分
我个人只是对APDS-9960中的Color / ALS功能感兴趣,因此我决定更详细地考虑它,并编写了一些代码来演示其操作。
我有意使代码尽可能紧凑,简洁,并且易于理解。 所有代码将在文章末尾显示。
因此,该模块的所有文档(图纸,引脚图和电路图)都可以在制造商的网站上找到 。

将我们的APDS-9960模块连接到STM32VLDISCOVERY
APDS9960使用i2c接口与外界通信,因此对于STM32VLDISCOVERY,我们通过将SCL模块引脚连接到PB6引脚以及将SDA引脚连接到PB7引脚来使用I2C1总线。 不要忘记连接电源线和公共线。 在这种情况下将不使用中断,因此可以省略Int的输出。 在我的照片中它已连接,但未使用。

现在有一点代码。 由于与模块的所有通信都是使用i2c进行的,因此我们将创建必要的配置并定义i2c的读/写功能。
I2C的初始化。
初始化void I2C1_init(void) { I2C_InitTypeDef I2C_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB| RCC_APB2Periph_AFIO , ENABLE); GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; GPIO_Init(GPIOB, &GPIO_InitStructure); I2C_StructInit(&I2C_InitStructure); I2C_InitStructure.I2C_ClockSpeed = 100000; I2C_InitStructure.I2C_OwnAddress1 = 0x01; I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; I2C_Init(I2C1, &I2C_InitStructure); I2C_Cmd(I2C1, ENABLE); }
读取寄存器。
从寄存器读取值的功能 uint8_t i2c1_read(uint8_t addr) { uint8_t data; while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)); I2C_GenerateSTART(I2C1, ENABLE); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); I2C_Send7bitAddress(I2C1, APDS9960_I2C_ADDR<<1, I2C_Direction_Transmitter); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); I2C_SendData(I2C1, addr); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); I2C_GenerateSTART(I2C1, ENABLE); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); I2C_Send7bitAddress(I2C1, APDS9960_I2C_ADDR<<1, I2C_Direction_Receiver); while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED)); data = I2C_ReceiveData(I2C1); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)); I2C_AcknowledgeConfig(I2C1, DISABLE); I2C_GenerateSTOP(I2C1, ENABLE); while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)); return data; }
写值注册
寄存器值功能 void i2c1_write(uint8_t addr, uint8_t data) { I2C_GenerateSTART(I2C1, ENABLE); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); I2C_Send7bitAddress(I2C1, APDS9960_I2C_ADDR<<1, I2C_Direction_Transmitter); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); I2C_SendData(I2C1, addr); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); I2C_SendData(I2C1, data); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); I2C_GenerateSTOP(I2C1, ENABLE); while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)) {}; }
为了使模块正常工作,必须首先对其进行正确配置。 专门用于颜色识别和照明,必须执行以下操作:
1)定义ATIME寄存器。 默认情况下,模块启动时,ATIME寄存器的值为0xFF,如果不进行任何更改,则将影响传感器的灵敏度-灵敏度较低。
i2c1_write(APDS9960_ATIME, DEFAULT_ATIME);
2)在下一步中,我们将控制寄存器一个寄存器(0x8F)的参数字段AGAIN(ALS和色彩增益控制)设置为对应于等于x4的增益的值(DEFAULT_AGAIN等于AGAIN_4X)。
i2c1_write(APDS9960_CONTROL, DEFAULT_AGAIN);
3)通过将启用寄存器寄存器(0x80)的AEN位置1来启用ALS选项
4)通过设置同一寄存器的PON位来打开模块的电源
像这样:
i2c1_write(APDS9960_ENABLE, (APDS9960_PON | APDS9960_AEN));
这就是整个设置。 我们的传感器已准备好工作和防御,您可以开始测量所有颜色。
但首先,请测量照明水平
Colour_tmpL = i2c1_read(APDS9960_CDATAL); Colour_tmpH = i2c1_read(APDS9960_CDATAH); Colour_Clear = (Colour_tmpH << 8) + Colour_tmpL;
现在我们的业务已经到了期待已久的鲜花
现在整个代码:
main.c #include "stm32f10x.h" #define APDS9960_I2C_ADDR 0x39 #define APDS9960_ATIME 0x81 #define APDS9960_CONTROL 0x8F #define APDS9960_ENABLE 0x80 #define APDS9960_CDATAL 0x94 #define APDS9960_CDATAH 0x95 #define APDS9960_RDATAL 0x96 #define APDS9960_RDATAH 0x97 #define APDS9960_GDATAL 0x98 #define APDS9960_GDATAH 0x99 #define APDS9960_BDATAL 0x9A #define APDS9960_BDATAH 0x9B #define APDS9960_PON 0x01 #define APDS9960_AEN 0x02 #define APDS9960_PEN 0x04 #define APDS9960_WEN 0x08 #define APSD9960_AIEN 0x10 #define APDS9960_PIEN 0x20 #define APDS9960_GEN 0x40 #define APDS9960_GVALID 0x01 #define AGAIN_1X 0 #define AGAIN_4X 1 #define AGAIN_16X 2 #define AGAIN_64X 3 #define DEFAULT_ATIME 219
为了方便起见,我故意没有在单独的标头中定义常量。
顺便说一下,常量是从官方的SparkFun Electronics存储库中借用的。 从这里 。
我真的很喜欢APDS-9960,这很有趣,研究很有趣,写文章很有趣。 我希望有人会觉得这种材料有用。 谢谢您的关注。