Распознавание Цвета И Уровня Освещенности С Помощью Apds-9960.



Распознавание цвета и уровня освещенности с помощью APDS-9960.

Недавно мелькнуло на Хабре.

com статья о чем, помимо прочего, сообщил и датчик освещенности.

Некоторое время назад я нашел и приобрел интересную вещь — модуль производства RobotDyn на базе датчика APDS-9960, который также умеет измерять уровень освещенности.

Порывшись и не найдя упоминаний об этом устройстве на этом ресурсе, я решил, что это подходящий повод написать статью.

В этой статье я хотел бы в общих чертах познакомить читателей с возможностями, которые предоставляет этот датчик, и более подробно рассмотреть, как с его помощью можно определять цвет и измерять уровень освещенности.

APDS-9960 — это датчик от Avago, комбинированный цифровой датчик с рядом различных интересных и полезных функций.

Он может распознавать жесты, определять близость, а также определять интенсивность окружающего света и определять цвет. Именно об этом мы и поговорим в этой статье — с помощью старого STM32VLDISCOVERY и APDS-9960 мы будем измерять освещенность и определять цвет во всем его богатстве оттенков красного, зеленого и синего.

Однако прежде чем мы перейдем к практической части, позвольте мне сначала написать несколько слов об общих возможностях APDS-9960. Функциональная схема APDS-9960 представлена на рисунке ниже.



Распознавание цвета и уровня освещенности с помощью APDS-9960.

Распознавание жестов Представление о том, как выглядит распознавание жестов на APDS-9960, показано здесь очень хорошо.

видео .

В документации описан принцип регистрации жестов: Для распознавания жеста используются четыре направленных фотодиода, которые регистрируют отраженный свет (в ИК-диапазоне), излучаемый встроенным светодиодом.



Распознавание цвета и уровня освещенности с помощью APDS-9960.

Функция обнаружения приближения Судя по описанию из той же документации, механизм обнаружения (близости) работает точно по тому же принципу, что и распознавание жестов.

Распознавание цвета и уровень окружающего освещения (Color/ALS) Согласно функциональной схеме датчик определяет уровень цвета/освещенности с помощью соответствующих фотодиодов.

Также заявлено, что APDS-9960 имеет встроенные фильтры, блокирующие ультрафиолетовый и инфракрасный диапазоны.

Упрощенно это выглядит так: сигналы, записанные фотодиодами, измеряются с помощью АЦП, заносятся в буфер, а затем данные отправляются по i2c.

Распознавание цвета и уровня освещенности с помощью APDS-9960.

Графики на картинке выше взяты из документации к датчику; спектральная характеристика Color Sense (RGBC) показана вверху слева.

Сигнал фотодиода RGBC накапливается в течение периода времени, установленного значением регистра ATIME. В SparkFun (в их «apds9960.h») это значение определяется константой DEFAULT_ATIME и равно 219, что соответствует 103 мс.

Усиление регулируется от 1x до 64x и определяется настройкой параметра CONTROL AGAIN. Константа DEFAULT_AGAIN равна 1, что соответствует выигрышу в 4 раза.

Практическая часть Лично меня интересовала только функция Color/ALS в APDS-9960, поэтому я решил рассмотреть ее подробнее и написал небольшой код, демонстрирующий ее работу.

Я сознательно старался сделать код максимально компактным, лаконичным и предельно простым для понимания; весь код будет представлен в конце статьи.

Итак, вся документация (чертеж, распиновка и принципиальная схема) на модуль доступна на сайте.

Веб-сайт производитель.



Распознавание цвета и уровня освещенности с помощью APDS-9960.

Подключим наш модуль APDS-9960 к STM32VLDISCOVERY. APDS9960 использует интерфейс i2c для связи с внешним миром, поэтому для STM32VLDISCOVERY мы используем шину I2C1, подключив вывод модуля SCL к выводу PB6, а вывод SDA соответственно к выводу PB7. Не забудьте подключить питание и общий провод. Прерывания в этом случае использоваться не будут, поэтому вывод Int подключать не нужно.

На моем фото он подключен, но не используется.



Распознавание цвета и уровня освещенности с помощью APDS-9960.

А теперь немного кода.

Поскольку вся связь с модулем происходит с помощью 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) следующим шагом является установка поля параметра AGAIN (ALS и Color Gain Control) регистра Control Register One (0x8F) в значение, соответствующее коэффициенту усиления, равному х4 (DEFAULT_AGAIN равен AGAIN_4X).



i2c1_write(APDS9960_CONTROL, DEFAULT_AGAIN);

3) включить опцию ALS, установив бит AEN регистра Enable Register (0x80) 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;

И вот наше дело дошло до долгожданных цветов.

Давайте получим данные RGB

//_________________________________________________________________________ // RED color Recognize: Colour_tmpL = i2c1_read(APDS9960_RDATAL); Colour_tmpH = i2c1_read(APDS9960_RDATAH); Colour_Red = (Colour_tmpH << 8) + Colour_tmpL; //_________________________________________________________________________ // GREEN color Recognize: Colour_tmpL = i2c1_read(APDS9960_GDATAL); Colour_tmpH = i2c1_read(APDS9960_GDATAH); Colour_Green = (Colour_tmpH << 8) + Colour_tmpL; //_________________________________________________________________________ // BLUE color Recognize: Colour_tmpL = i2c1_read(APDS9960_BDATAL); Colour_tmpH = i2c1_read(APDS9960_BDATAH); Colour_Blue = (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 /* Bit fields */ #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 /* ALS Gain (AGAIN) values */ #define AGAIN_1X 0 #define AGAIN_4X 1 #define AGAIN_16X 2 #define AGAIN_64X 3 #define DEFAULT_ATIME 219 // 103ms #define DEFAULT_AGAIN AGAIN_4X uint8_t Colour_tmpL = 0; uint8_t Colour_tmpH = 0; uint16_t Colour_Clear = 0; uint16_t Colour_Red = 0; uint16_t Colour_Green = 0; uint16_t Colour_Blue = 0; //----------------------------------------------------------------------- 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)) {}; } //----------------------------------------------------------------------- int main() { I2C1_init(); i2c1_write(APDS9960_ATIME, DEFAULT_ATIME); i2c1_write(APDS9960_CONTROL, DEFAULT_AGAIN); i2c1_write(APDS9960_ENABLE, (APDS9960_PON | APDS9960_AEN)); while (1) { Colour_Clear = 0; Colour_Red = 0; Colour_Green = 0; Colour_Blue = 0; //_________________________________________________________________________ // Ambient Light Recognize: Colour_tmpL = i2c1_read(APDS9960_CDATAL); Colour_tmpH = i2c1_read(APDS9960_CDATAH); Colour_Clear = (Colour_tmpH << 8) + Colour_tmpL; //_________________________________________________________________________ // RED color Recognize: Colour_tmpL = i2c1_read(APDS9960_RDATAL); Colour_tmpH = i2c1_read(APDS9960_RDATAH); Colour_Red = (Colour_tmpH << 8) + Colour_tmpL; //_________________________________________________________________________ // GREEN color Recognize: Colour_tmpL = i2c1_read(APDS9960_GDATAL); Colour_tmpH = i2c1_read(APDS9960_GDATAH); Colour_Green = (Colour_tmpH << 8) + Colour_tmpL; //_________________________________________________________________________ // BLUE color Recognize: Colour_tmpL = i2c1_read(APDS9960_BDATAL); Colour_tmpH = i2c1_read(APDS9960_BDATAH); Colour_Blue = (Colour_tmpH << 8) + Colour_tmpL; } }

Определения констант я намеренно не вынес в отдельный шапку для удобства.

Константы, кстати, я позаимствовал из официального репозитория SparkFun Electronics. Здесь отсюда .

Мне очень понравился APDS-9960 - интересная штука, было интересно исследовать, интересно было написать статью.

Надеюсь, этот материал будет кому-то полезен.

Спасибо за внимание.

Теги: #Программирование микроконтроллеров #stm32 #Сделай сам или Сделай сам #Электроника для начинающих #поделки #APDS-9960

Вместе с данным постом часто просматривают: