Arduino Uno + APDS9930 实现手势控制LED灯亮灭、调光等

前言

开发板:Arduino Uno Rev3 创客主板
开发环境:Arduino IDE
开发语言:Arduino 语言(类C语言)
模块:APDS9930
在这里插入图片描述
在这里插入图片描述

源码参考:https://github.com/Depau/APDS9930

功能介绍:

1、靠近亮灯、距离保持约10cm常亮,远离延时熄灭

当有物体靠近传感器约10cm的位置时,触发中断,点亮LED LIGHT_TIME毫秒,持续触发则常亮,无则灭灯。 通过修改 宏定义 LIGHT_TIME调节延时,LED负极接在数字10口(正极 3.3V供电)

2、靠近点亮/熄灭LED,延时期间操作不响应

当有物体靠近传感器约10cm的位置时,触发中断,点亮/熄灭LED,延时RESPONSE_TIME毫秒,延时期间操作不响应。 通过修改 宏定义 RESPONSE_TIME调节延时响应。

3、挥手点亮/熄灭LED,悬停进行非无极pwm调光

当有物体靠近传感器约10cm的位置时,可以触发中断。

  • 如果4RESPONSE_TIME毫秒内 没有触发4次中断,即4RESPONSE_TIME毫秒内,划过传感区域,则为开关模式,会进行LED的亮灭操作(亮到设定的pwm_val)
  • 如果4RESPONSE_TIME毫秒内 触发了4次中断,即4RESPONSE_TIME毫秒以上,物体一直停留在传感区域内,则为pwm调光模式,会进行LED的pwm非无极调光(每次在当前基础上增加PWM_CHANGE_VAL)
  • 如果在pwm调光模式下,物体移出了传感区域,则会结束pwm值的调节。若下次继续快划,则进行开关,若继续悬停,则继续调光。
  • 单位延时RESPONSE_TIME毫秒,延时期间操作不响应。
  • 通过修改 宏定义 RESPONSE_TIME调节延时响应,若想增加调光速率,可减小此值。
  • 通过修改 宏定义 PWM_CHANGE_VAL,调节单次pwm调光的大小,范围1-255。若想要更细致的调光,可减小此值。

接线

 Arduino Pin  APDS-9930 Board  Function
 
 3.3V         VL               据说用作参考电压,得接上
 3.3V         VCC              Power
 GND          GND              Ground
 A4           SDA              I2C Data
 A5           SCL              I2C Clock
 2            INT              Interrupt
 10           -                LED

在这里插入图片描述

效果图

Arduino+APDS9930 实现手势控制灯亮灭、调光等

源码

在这里插入图片描述

通用部分

APDS9930.cpp

/**
   @file    APDS-9930.cpp
   @brief   Library for the SparkFun APDS-9930 breakout board
   @author  Shawn Hymel (SparkFun Electronics)

   @copyright	This code is public domain but you buy me a beer if you use
   this and we meet someday (Beerware license).

   This library interfaces the Avago APDS-9930 to Arduino over I2C. The library
   relies on the Arduino Wire (I2C) library. to use the library, instantiate an
   APDS9930 object, call init(), and call the appropriate functions.

   APDS-9930 current draw tests (default parameters):
     Off:                   1mA
     Waiting for gesture:   14mA
     Gesture in progress:   35mA
*/

#include <Arduino.h>
#include <Wire.h>

#include "APDS9930.h"

/**
   @brief Constructor - Instantiates APDS9930 object
*/
APDS9930::APDS9930()
{

}

/**
   @brief Destructor
*/
APDS9930::~APDS9930()
{

}

/**
   @brief Configures I2C communications and initializes registers to defaults

   @return True if initialized successfully. False otherwise.
*/
bool APDS9930::init()
{
  uint8_t id;

  /* Initialize I2C */
  Wire.begin();

  /* Read ID register and check against known values for APDS-9930 */
  if ( !wireReadDataByte(APDS9930_ID, id) ) {
    Serial.println(F("ID read"));
    return false;
  }
  if ( !(id == APDS9930_ID_1 || id == APDS9930_ID_2) ) {
    Serial.println(F("ID check"));
    Serial.println(String("ID is ") + String(id, HEX));
    //return false;
  }

  /* Set ENABLE register to 0 (disable all features) */
  if ( !setMode(ALL, OFF) ) {
    Serial.println(F("Regs off"));
    return false;
  }

  /* Set default values for ambient light and proximity registers */
  if ( !wireWriteDataByte(APDS9930_ATIME, DEFAULT_ATIME) ) {
    return false;
  }
  if ( !wireWriteDataByte(APDS9930_WTIME, DEFAULT_WTIME) ) {
    return false;
  }
  if ( !wireWriteDataByte(APDS9930_PPULSE, DEFAULT_PPULSE) ) {
    return false;
  }
  if ( !wireWriteDataByte(APDS9930_POFFSET, DEFAULT_POFFSET) ) {
    return false;
  }
  if ( !wireWriteDataByte(APDS9930_CONFIG, DEFAULT_CONFIG) ) {
    return false;
  }
  if ( !setLEDDrive(DEFAULT_PDRIVE) ) {
    return false;
  }
  if ( !setProximityGain(DEFAULT_PGAIN) ) {
    return false;
  }
  if ( !setAmbientLightGain(DEFAULT_AGAIN) ) {
    return false;
  }
  if ( !setProximityDiode(DEFAULT_PDIODE) ) {
    return false;
  }
  if ( !setProximityIntLowThreshold(DEFAULT_PILT) ) {
    return false;
  }
  if ( !setProximityIntHighThreshold(DEFAULT_PIHT) ) {
    return false;
  }
  if ( !setLightIntLowThreshold(DEFAULT_AILT) ) {
    return false;
  }
  if ( !setLightIntHighThreshold(DEFAULT_AIHT) ) {
    return false;
  }
  if ( !wireWriteDataByte(APDS9930_PERS, DEFAULT_PERS) ) {
    return false;
  }

  return true;
}

/*******************************************************************************
   Public methods for controlling the APDS-9930
 ******************************************************************************/

/**
   @brief Reads and returns the contents of the ENABLE register

   @return Contents of the ENABLE register. 0xFF if error.
*/
uint8_t APDS9930::getMode()
{
  uint8_t enable_value;

  /* Read current ENABLE register */
  if ( !wireReadDataByte(APDS9930_ENABLE, enable_value) ) {
    return ERROR;
  }

  return enable_value;
}

/**
   @brief Enables or disables a feature in the APDS-9930

   @param[in] mode which feature to enable
   @param[in] enable ON (1) or OFF (0)
   @return True if operation success. False otherwise.
*/
bool APDS9930::setMode(uint8_t mode, uint8_t enable)
{
  uint8_t reg_val;

  /* Read current ENABLE register */
  reg_val = getMode();
  if ( reg_val == ERROR ) {
    return false;
  }

  /* Change bit(s) in ENABLE register */
  enable = enable & 0x01;
  if ( mode >= 0 && mode <= 6 ) {
    if (enable) {
      reg_val |= (1 << mode);
    } else {
      reg_val &= ~(1 << mode);
    }
  } else if ( mode == ALL ) {
    if (enable) {
      reg_val = 0x7F;
    } else {
      reg_val = 0x00;
    }
  }

  /* Write value back to ENABLE register */
  if ( !wireWriteDataByte(APDS9930_ENABLE, reg_val) ) {
    return false;
  }

  return true;
}

/**
   @brief Starts the light (Ambient/IR) sensor on the APDS-9930

   @param[in] interrupts true to enable hardware interrupt on high or low light
   @return True if sensor enabled correctly. False on error.
*/
bool APDS9930::enableLightSensor(bool interrupts)
{

  /* Set default gain, interrupts, enable power, and enable sensor */
  if ( !setAmbientLightGain(DEFAULT_AGAIN) ) {
    return false;
  }
  if ( interrupts ) {
    if ( !setAmbientLightIntEnable(1) ) {
      return false;
    }
  } else {
    if ( !setAmbientLightIntEnable(0) ) {
      return false;
    }
  }
  if ( !enablePower() ) {
    return false;
  }
  if ( !setMode(AMBIENT_LIGHT, 1) ) {
    return false;
  }

  return true;

}

/**
   @brief Ends the light sensor on the APDS-9930

   @return True if sensor disabled correctly. False on error.
*/
bool APDS9930::disableLightSensor()
{
  if ( !setAmbientLightIntEnable(0) ) {
    return false;
  }
  if ( !setMode(AMBIENT_LIGHT, 0) ) {
    return false;
  }

  return true;
}

/**
   @brief Starts the proximity sensor on the APDS-9930

   @param[in] interrupts true to enable hardware external interrupt on proximity
   @return True if sensor enabled correctly. False on error.
*/
bool APDS9930::enableProximitySensor(bool interrupts)
{
  /* Set default gain, LED, interrupts, enable power, and enable sensor */
  if ( !setProximityGain(DEFAULT_PGAIN) ) {
    return false;
  }
  if ( !setLEDDrive(DEFAULT_PDRIVE) ) {
    return false;
  }
  if ( interrupts ) {
    if ( !setProximityIntEnable(1) ) {
      return false;
    }
  } else {
    if ( !setProximityIntEnable(0) ) {
      return false;
    }
  }
  if ( !enablePower() ) {
    return false;
  }
  if ( !setMode(PROXIMITY, 1) ) {
    return false;
  }

  return true;
}

/**
   @brief Ends the proximity sensor on the APDS-9930

   @return True if sensor disabled correctly. False on error.
*/
bool APDS9930::disableProximitySensor()
{
  if ( !setProximityIntEnable(0) ) {
    return false;
  }
  if ( !setMode(PROXIMITY, 0) ) {
    return false;
  }

  return true;
}

/**
   Turn the APDS-9930 on

   @return True if operation successful. False otherwise.
*/
bool APDS9930::enablePower()
{
  if ( !setMode(POWER, 1) ) {
    return false;
  }

  return true;
}

/**
   Turn the APDS-9930 off

   @return True if operation successful. False otherwise.
*/
bool APDS9930::disablePower()
{
  if ( !setMode(POWER, 0) ) {
    return false;
  }

  return true;
}

/*******************************************************************************
   Ambient light sensor controls
 ******************************************************************************/

/**
   @brief Reads the ambient (clear) light level as a 16-bit value

   @param[out] val value of the light sensor.
   @return True if operation successful. False otherwise.
*/
bool APDS9930::readAmbientLightLux(float &val)
{
  uint16_t Ch0;
  uint16_t Ch1;

  /* Read value from channel 0 */
  if ( !readCh0Light(Ch0) ) {
    return false;
  }

  /* Read value from channel 1 */
  if ( !readCh1Light(Ch1) ) {
    return false;
  }

  val = floatAmbientToLux(Ch0, Ch1);
  return true;
}

bool APDS9930::readAmbientLightLux(unsigned long &val)
{
  uint16_t Ch0;
  uint16_t Ch1;

  /* Read value from channel 0 */
  if ( !readCh0Light(Ch0) ) {
    return false;
  }

  /* Read value from channel 1 */
  if ( !readCh1Light(Ch1) ) {
    return false;
  }

  val = ulongAmbientToLux(Ch0, Ch1);
  return true;
}

float APDS9930::floatAmbientToLux(uint16_t Ch0, uint16_t Ch1)
{
  uint8_t x[4] = {1, 8, 16, 120};
  float ALSIT = 2.73 * (256 - DEFAULT_ATIME);
  float iac  = max(Ch0 - ALS_B * Ch1, ALS_C * Ch0 - ALS_D * Ch1);
  if (iac < 0) iac = 0;
  float lpc  = GA * DF / (ALSIT * x[getAmbientLightGain()]);
  return iac * lpc;
}

unsigned long APDS9930::ulongAmbientToLux(uint16_t Ch0, uint16_t Ch1)
{
  uint8_t x[4] = {1, 8, 16, 120};
  unsigned long ALSIT = 2.73 * (256 - DEFAULT_ATIME);
  unsigned long iac  = max(Ch0 - ALS_B * Ch1, ALS_C * Ch0 - ALS_D * Ch1);
  if (iac < 0) iac = 0;
  unsigned long lpc  = GA * DF / (ALSIT * x[getAmbientLightGain()]);
  return iac * lpc;
}

bool APDS9930::readCh0Light(uint16_t &val)
{
  uint8_t val_byte;
  val = 0;

  /* Read value from channel 0 */
  if ( !wireReadDataByte(APDS9930_Ch0DATAL, val_byte) ) {
    return false;
  }
  val = val_byte;
  if ( !wireReadDataByte(APDS9930_Ch0DATAH, val_byte) ) {
    return false;
  }
  val += ((uint16_t)val_byte << 8);
  return true;
}

bool APDS9930::readCh1Light(uint16_t &val)
{
  uint8_t val_byte;
  val = 0;

  /* Read value from channel 0 */
  if ( !wireReadDataByte(APDS9930_Ch1DATAL, val_byte) ) {
    return false;
  }
  val = val_byte;
  if ( !wireReadDataByte(APDS9930_Ch1DATAH, val_byte) ) {
    return false;
  }
  val += ((uint16_t)val_byte << 8);
  return true;
}

/*******************************************************************************
   Proximity sensor controls
 ******************************************************************************/

/**
   @brief Reads the proximity level as an 8-bit value

   @param[out] val value of the proximity sensor.
   @return True if operation successful. False otherwise.
*/
bool APDS9930::readProximity(uint16_t &val)
{
  val = 0;
  uint8_t val_byte;

  /* Read value from proximity data register */
  if ( !wireReadDataByte(APDS9930_PDATAL, val_byte) ) {
    return false;
  }
  val = val_byte;
  if ( !wireReadDataByte(APDS9930_PDATAH, val_byte) ) {
    return false;
  }
  val += ((uint16_t)val_byte << 8);

  return true;
}

/*******************************************************************************
   Getters and setters for register values
 ******************************************************************************/

/**
   @brief Returns the lower threshold for proximity detection

   @return lower threshold
*/
uint16_t APDS9930::getProximityIntLowThreshold()
{
  uint16_t val;
  uint8_t val_byte;

  /* Read value from PILT register */
  if ( !wireReadDataByte(APDS9930_PILTL, val_byte) ) {
    val = 0;
  }
  val = val_byte;
  if ( !wireReadDataByte(APDS9930_PILTH, val_byte) ) {
    val = 0;
  }
  val |= ((uint16_t)val_byte << 8);

  return val;
}

/**
   @brief Sets the lower threshold for proximity detection

   @param[in] threshold the lower proximity threshold
   @return True if operation successful. False otherwise.
*/
bool APDS9930::setProximityIntLowThreshold(uint16_t threshold)
{
  uint8_t lo;
  uint8_t hi;
  hi = threshold >> 8;
  lo = threshold & 0x00FF;

  if ( !wireWriteDataByte(APDS9930_PILTL, lo) ) {
    return false;
  }
  if ( !wireWriteDataByte(APDS9930_PILTH, hi) ) {
    return false;
  }

  return true;
}

/**
   @brief Returns the high threshold for proximity detection

   @return high threshold
*/
uint16_t APDS9930::getProximityIntHighThreshold()
{
  uint16_t val;
  uint8_t val_byte;

  /* Read value from PILT register */
  if ( !wireReadDataByte(APDS9930_PIHTL, val_byte) ) {
    val = 0;
  }
  val = val_byte;
  if ( !wireReadDataByte(APDS9930_PIHTH, val_byte) ) {
    val = 0;
  }
  val |= ((uint16_t)val_byte << 8);

  return val;
}

/**
   @brief Sets the high threshold for proximity detection

   @param[in] threshold the high proximity threshold
   @return True if operation successful. False otherwise.
*/
bool APDS9930::setProximityIntHighThreshold(uint16_t threshold)
{
  uint8_t lo;
  uint8_t hi;
  hi = threshold >> 8;
  lo = threshold & 0x00FF;

  if ( !wireWriteDataByte(APDS9930_PIHTL, lo) ) {
    return false;
  }
  if ( !wireWriteDataByte(APDS9930_PIHTH, hi) ) {
    return false;
  }

  return true;
}

/**
   @brief Returns LED drive strength for proximity and ALS

   Value    LED Current
     0        100 mA
     1         50 mA
     2         25 mA
     3         12.5 mA

   @return the value of the LED drive strength. 0xFF on failure.
*/
uint8_t APDS9930::getLEDDrive()
{
  uint8_t val;

  /* Read value from CONTROL register */
  if ( !wireReadDataByte(APDS9930_CONTROL, val) ) {
    return ERROR;
  }

  /* Shift and mask out LED drive bits */
  val = (val >> 6) & 0b00000011;

  return val;
}

/**
   @brief Sets the LED drive strength for proximity and ALS

   Value    LED Current
     0        100 mA
     1         50 mA
     2         25 mA
     3         12.5 mA

   @param[in] drive the value (0-3) for the LED drive strength
   @return True if operation successful. False otherwise.
*/
bool APDS9930::setLEDDrive(uint8_t drive)
{
  uint8_t val;

  /* Read value from CONTROL register */
  if ( !wireReadDataByte(APDS9930_CONTROL, val) ) {
    return false;
  }

  /* Set bits in register to given value */
  drive &= 0b00000011;
  drive = drive << 6;
  val &= 0b00111111;
  val |= drive;

  /* Write register value back into CONTROL register */
  if ( !wireWriteDataByte(APDS9930_CONTROL, val) ) {
    return false;
  }

  return true;
}

/**
   @brief Returns receiver gain for proximity detection

   Value    Gain
     0       1x
     1       2x
     2       4x
     3       8x

   @return the value of the proximity gain. 0xFF on failure.
*/
uint8_t APDS9930::getProximityGain()
{
  uint8_t val;

  /* Read value from CONTROL register */
  if ( !wireReadDataByte(APDS9930_CONTROL, val) ) {
    return ERROR;
  }

  /* Shift and mask out PDRIVE bits */
  val = (val >> 2) & 0b00000011;

  return val;
}

/**
   @brief Sets the receiver gain for proximity detection

   Value    Gain
     0       1x
     1       2x
     2       4x
     3       8x

   @param[in] drive the value (0-3) for the gain
   @return True if operation successful. False otherwise.
*/
bool APDS9930::setProximityGain(uint8_t drive)
{
  uint8_t val;

  /* Read value from CONTROL register */
  if ( !wireReadDataByte(APDS9930_CONTROL, val) ) {
    return false;
  }

  /* Set bits in register to given value */
  drive &= 0b00000011;
  drive = drive << 2;
  val &= 0b11110011;
  val |= drive;

  /* Write register value back into CONTROL register */
  if ( !wireWriteDataByte(APDS9930_CONTROL, val) ) {
    return false;
  }

  return true;
}

/**
   @brief Returns the proximity diode

   Value    Diode selection
     0       Reserved
     1       Reserved
     2       Use Ch1 diode
     3       Reserved

   @return the selected diode. 0xFF on failure.
*/
uint8_t APDS9930::getProximityDiode()
{
  uint8_t val;

  /* Read value from CONTROL register */
  if ( !wireReadDataByte(APDS9930_CONTROL, val) ) {
    return ERROR;
  }

  /* Shift and mask out PDRIVE bits */
  val = (val >> 4) & 0b00000011;

  return val;
}

/**
   @brief Selects the proximity diode

   Value    Diode selection
     0       Reserved
     1       Reserved
     2       Use Ch1 diode
     3       Reserved

   @param[in] drive the value (0-3) for the diode
   @return True if operation successful. False otherwise.
*/
bool APDS9930::setProximityDiode(uint8_t drive)
{
  uint8_t val;

  /* Read value from CONTROL register */
  if ( !wireReadDataByte(APDS9930_CONTROL, val) ) {
    return false;
  }

  /* Set bits in register to given value */
  drive &= 0b00000011;
  drive = drive << 4;
  val &= 0b11001111;
  val |= drive;

  /* Write register value back into CONTROL register */
  if ( !wireWriteDataByte(APDS9930_CONTROL, val) ) {
    return false;
  }

  return true;
}

/**
   @brief Returns receiver gain for the ambient light sensor (ALS)

   Value    Gain
     0        1x
     1        4x
     2       16x
     3      120x

   @return the value of the ALS gain. 0xFF on failure.
*/
uint8_t APDS9930::getAmbientLightGain()
{
  uint8_t val;

  /* Read value from CONTROL register */
  if ( !wireReadDataByte(APDS9930_CONTROL, val) ) {
    return ERROR;
  }

  /* Shift and mask out ADRIVE bits */
  val &= 0b00000011;

  return val;
}

/**
   @brief Sets the receiver gain for the ambient light sensor (ALS)

   Value    Gain
     0        1x
     1        4x
     2       16x
     3       64x

   @param[in] drive the value (0-3) for the gain
   @return True if operation successful. False otherwise.
*/
bool APDS9930::setAmbientLightGain(uint8_t drive)
{
  uint8_t val;

  /* Read value from CONTROL register */
  if ( !wireReadDataByte(APDS9930_CONTROL, val) ) {
    return false;
  }

  /* Set bits in register to given value */
  drive &= 0b00000011;
  val &= 0b11111100;
  val |= drive;

  /* Write register value back into CONTROL register */
  if ( !wireWriteDataByte(APDS9930_CONTROL, val) ) {
    return false;
  }

  return true;
}

/**
   @brief Gets the low threshold for ambient light interrupts

   @param[out] threshold current low threshold stored on the APDS-9930
   @return True if operation successful. False otherwise.
*/
bool APDS9930::getLightIntLowThreshold(uint16_t &threshold)
{
  uint8_t val_byte;
  threshold = 0;

  /* Read value from ambient light low threshold, low byte register */
  if ( !wireReadDataByte(APDS9930_AILTL, val_byte) ) {
    return false;
  }
  threshold = val_byte;

  /* Read value from ambient light low threshold, high byte register */
  if ( !wireReadDataByte(APDS9930_AILTH, val_byte) ) {
    return false;
  }
  threshold = threshold + ((uint16_t)val_byte << 8);

  return true;
}

/**
   @brief Sets the low threshold for ambient light interrupts

   @param[in] threshold low threshold value for interrupt to trigger
   @return True if operation successful. False otherwise.
*/
bool APDS9930::setLightIntLowThreshold(uint16_t threshold)
{
  uint8_t val_low;
  uint8_t val_high;

  /* Break 16-bit threshold into 2 8-bit values */
  val_low = threshold & 0x00FF;
  val_high = (threshold & 0xFF00) >> 8;

  /* Write low byte */
  if ( !wireWriteDataByte(APDS9930_AILTL, val_low) ) {
    return false;
  }

  /* Write high byte */
  if ( !wireWriteDataByte(APDS9930_AILTH, val_high) ) {
    return false;
  }

  return true;
}

/**
   @brief Gets the high threshold for ambient light interrupts

   @param[out] threshold current low threshold stored on the APDS-9930
   @return True if operation successful. False otherwise.
*/
bool APDS9930::getLightIntHighThreshold(uint16_t &threshold)
{
  uint8_t val_byte;
  threshold = 0;

  /* Read value from ambient light high threshold, low byte register */
  if ( !wireReadDataByte(APDS9930_AIHTL, val_byte) ) {
    return false;
  }
  threshold = val_byte;

  /* Read value from ambient light high threshold, high byte register */
  if ( !wireReadDataByte(APDS9930_AIHTH, val_byte) ) {
    return false;
  }
  threshold = threshold + ((uint16_t)val_byte << 8);

  return true;
}

/**
   @brief Sets the high threshold for ambient light interrupts

   @param[in] threshold high threshold value for interrupt to trigger
   @return True if operation successful. False otherwise.
*/
bool APDS9930::setLightIntHighThreshold(uint16_t threshold)
{
  uint8_t val_low;
  uint8_t val_high;

  /* Break 16-bit threshold into 2 8-bit values */
  val_low = threshold & 0x00FF;
  val_high = (threshold & 0xFF00) >> 8;

  /* Write low byte */
  if ( !wireWriteDataByte(APDS9930_AIHTL, val_low) ) {
    return false;
  }

  /* Write high byte */
  if ( !wireWriteDataByte(APDS9930_AIHTH, val_high) ) {
    return false;
  }

  return true;
}


/**
   @brief Gets if ambient light interrupts are enabled or not

   @return 1 if interrupts are enabled, 0 if not. 0xFF on error.
*/
uint8_t APDS9930::getAmbientLightIntEnable()
{
  uint8_t val;

  /* Read value from ENABLE register */
  if ( !wireReadDataByte(APDS9930_ENABLE, val) ) {
    return ERROR;
  }

  /* Shift and mask out AIEN bit */
  val = (val >> 4) & 0b00000001;

  return val;
}

/**
   @brief Turns ambient light interrupts on or off

   @param[in] enable 1 to enable interrupts, 0 to turn them off
   @return True if operation successful. False otherwise.
*/
bool APDS9930::setAmbientLightIntEnable(uint8_t enable)
{
  uint8_t val;

  /* Read value from ENABLE register */
  if ( !wireReadDataByte(APDS9930_ENABLE, val) ) {
    return false;
  }

  /* Set bits in register to given value */
  enable &= 0b00000001;
  enable = enable << 4;
  val &= 0b11101111;
  val |= enable;

  /* Write register value back into ENABLE register */
  if ( !wireWriteDataByte(APDS9930_ENABLE, val) ) {
    return false;
  }

  return true;
}

/**
   @brief Gets if proximity interrupts are enabled or not

   @return 1 if interrupts are enabled, 0 if not. 0xFF on error.
*/
uint8_t APDS9930::getProximityIntEnable()
{
  uint8_t val;

  /* Read value from ENABLE register */
  if ( !wireReadDataByte(APDS9930_ENABLE, val) ) {
    return ERROR;
  }

  /* Shift and mask out PIEN bit */
  val = (val >> 5) & 0b00000001;

  return val;
}

/**
   @brief Turns proximity interrupts on or off

   @param[in] enable 1 to enable interrupts, 0 to turn them off
   @return True if operation successful. False otherwise.
*/
bool APDS9930::setProximityIntEnable(uint8_t enable)
{
  uint8_t val;

  /* Read value from ENABLE register */
  if ( !wireReadDataByte(APDS9930_ENABLE, val) ) {
    return false;
  }

  /* Set bits in register to given value */
  enable &= 0b00000001;
  enable = enable << 5;
  val &= 0b11011111;
  val |= enable;

  /* Write register value back into ENABLE register */
  if ( !wireWriteDataByte(APDS9930_ENABLE, val) ) {
    return false;
  }

  return true;
}

/**
   @brief Clears the ambient light interrupt

   @return True if operation completed successfully. False otherwise.
*/
bool APDS9930::clearAmbientLightInt()
{
  if ( !wireWriteByte(CLEAR_ALS_INT) ) {
    return false;
  }

  return true;
}

/**
   @brief Clears the proximity interrupt

   @return True if operation completed successfully. False otherwise.
*/
bool APDS9930::clearProximityInt()
{
  if ( !wireWriteByte(CLEAR_PROX_INT) ) {
    return false;
  }

  return true;
}

/**
   @brief Clears all interrupts

   @return True if operation completed successfully. False otherwise.
*/
bool APDS9930::clearAllInts()
{
  if ( !wireWriteByte(CLEAR_ALL_INTS) ) {
    return false;
  }

  return true;
}

/*******************************************************************************
   Raw I2C Reads and Writes
 ******************************************************************************/

/**
   @brief Writes a single byte to the I2C device (no register)

   @param[in] val the 1-byte value to write to the I2C device
   @return True if successful write operation. False otherwise.
*/
bool APDS9930::wireWriteByte(uint8_t val)
{
  Wire.beginTransmission(APDS9930_I2C_ADDR);
  Wire.write(val);
  if ( Wire.endTransmission() != 0 ) {
    return false;
  }

  return true;
}

/**
   @brief Writes a single byte to the I2C device and specified register

   @param[in] reg the register in the I2C device to write to
   @param[in] val the 1-byte value to write to the I2C device
   @return True if successful write operation. False otherwise.
*/
bool APDS9930::wireWriteDataByte(uint8_t reg, uint8_t val)
{
  Wire.beginTransmission(APDS9930_I2C_ADDR);
  Wire.write(reg | AUTO_INCREMENT);
  Wire.write(val);
  if ( Wire.endTransmission() != 0 ) {
    return false;
  }

  return true;
}

/**
   @brief Writes a block (array) of bytes to the I2C device and register

   @param[in] reg the register in the I2C device to write to
   @param[in] val pointer to the beginning of the data byte array
   @param[in] len the length (in bytes) of the data to write
   @return True if successful write operation. False otherwise.
*/
bool APDS9930::wireWriteDataBlock(  uint8_t reg,
                                    uint8_t *val,
                                    unsigned int len)
{
  unsigned int i;

  Wire.beginTransmission(APDS9930_I2C_ADDR);
  Wire.write(reg | AUTO_INCREMENT);
  for (i = 0; i < len; i++) {
    Wire.beginTransmission(APDS9930_I2C_ADDR);
    Wire.write(val[i]);
  }
  if ( Wire.endTransmission() != 0 ) {
    return false;
  }

  return true;
}

/**
   @brief Reads a single byte from the I2C device and specified register

   @param[in] reg the register to read from
   @param[out] the value returned from the register
   @return True if successful read operation. False otherwise.
*/
bool APDS9930::wireReadDataByte(uint8_t reg, uint8_t &val)
{

  /* Indicate which register we want to read from */
  if (!wireWriteByte(reg | AUTO_INCREMENT)) {
    return false;
  }

  /* Read from register */
  Wire.requestFrom(APDS9930_I2C_ADDR, 1);
  while (Wire.available()) {
    val = Wire.read();
  }

  return true;
}


/**
   @brief Reads a block (array) of bytes from the I2C device and register

   @param[in] reg the register to read from
   @param[out] val pointer to the beginning of the data
   @param[in] len number of bytes to read
   @return Number of bytes read. -1 on read error.
*/
int APDS9930::wireReadDataBlock(   uint8_t reg,
                                   uint8_t *val,
                                   unsigned int len)
{
  unsigned char i = 0;

  /* Indicate which register we want to read from */
  if (!wireWriteByte(reg | AUTO_INCREMENT)) {
    return -1;
  }

  /* Read block data */
  Wire.requestFrom(APDS9930_I2C_ADDR, len);
  while (Wire.available()) {
    if (i >= len) {
      return -1;
    }
    val[i] = Wire.read();
    i++;
  }

  return i;
}

APDS9930.h

/**
   @file    APDS-9930.h
   @brief   Library for the SparkFun APDS-9930 breakout board
   @author  Shawn Hymel (SparkFun Electronics)

   @copyright	This code is public domain but you buy me a beer if you use
   this and we meet someday (Beerware license).

   This library interfaces the Avago APDS-9930 to Arduino over I2C. The library
   relies on the Arduino Wire (I2C) library. to use the library, instantiate an
   APDS9930 object, call init(), and call the appropriate functions.
*/

#ifndef APDS9930_H
#define APDS9930_H

#include <Arduino.h>

/* Debug */
#define DEBUG                   0

/* APDS-9930 I2C address */
#define APDS9930_I2C_ADDR       0x39

/* Command register modes */
#define REPEATED_BYTE           0x80
#define AUTO_INCREMENT          0xA0
#define SPECIAL_FN              0xE0

/* Error code for returned values */
#define ERROR                   0xFF

/* Acceptable device IDs */
#define APDS9930_ID_1           0x12
#define APDS9930_ID_2           0x39

/* Misc parameters */
#define FIFO_PAUSE_TIME         30      // Wait period (ms) between FIFO reads

/* APDS-9930 register addresses */
#define APDS9930_ENABLE         0x00
#define APDS9930_ATIME          0x01
#define APDS9930_PTIME          0x02
#define APDS9930_WTIME          0x03
#define APDS9930_AILTL          0x04
#define APDS9930_AILTH          0x05
#define APDS9930_AIHTL          0x06
#define APDS9930_AIHTH          0x07
#define APDS9930_PILTL          0x08
#define APDS9930_PILTH          0x09
#define APDS9930_PIHTL          0x0A
#define APDS9930_PIHTH          0x0B
#define APDS9930_PERS           0x0C
#define APDS9930_CONFIG         0x0D
#define APDS9930_PPULSE         0x0E
#define APDS9930_CONTROL        0x0F
#define APDS9930_ID             0x12
#define APDS9930_STATUS         0x13
#define APDS9930_Ch0DATAL       0x14
#define APDS9930_Ch0DATAH       0x15
#define APDS9930_Ch1DATAL       0x16
#define APDS9930_Ch1DATAH       0x17
#define APDS9930_PDATAL         0x18
#define APDS9930_PDATAH         0x19
#define APDS9930_POFFSET        0x1E


/* Bit fields */
#define APDS9930_PON            0b00000001
#define APDS9930_AEN            0b00000010
#define APDS9930_PEN            0b00000100
#define APDS9930_WEN            0b00001000
#define APSD9930_AIEN           0b00010000
#define APDS9930_PIEN           0b00100000
#define APDS9930_SAI            0b01000000

/* On/Off definitions */
#define OFF                     0
#define ON                      1

/* Acceptable parameters for setMode */
#define POWER                   0
#define AMBIENT_LIGHT           1
#define PROXIMITY               2
#define WAIT                    3
#define AMBIENT_LIGHT_INT       4
#define PROXIMITY_INT           5
#define SLEEP_AFTER_INT         6
#define ALL                     7

/* LED Drive values */
#define LED_DRIVE_100MA         0
#define LED_DRIVE_50MA          1
#define LED_DRIVE_25MA          2
#define LED_DRIVE_12_5MA        3

/* Proximity Gain (PGAIN) values */
#define PGAIN_1X                0
#define PGAIN_2X                1
#define PGAIN_4X                2
#define PGAIN_8X                3

/* ALS Gain (AGAIN) values */
#define AGAIN_1X                0
#define AGAIN_8X                1
#define AGAIN_16X               2
#define AGAIN_120X              3

/* Interrupt clear values */
#define CLEAR_PROX_INT          0xE5
#define CLEAR_ALS_INT           0xE6
#define CLEAR_ALL_INTS          0xE7

/* Default values */
#define DEFAULT_ATIME           0xED
#define DEFAULT_WTIME           0xFF
#define DEFAULT_PTIME           0xFF
#define DEFAULT_PPULSE          0x08
#define DEFAULT_POFFSET         0       // 0 offset
#define DEFAULT_CONFIG          0
#define DEFAULT_PDRIVE          LED_DRIVE_100MA
#define DEFAULT_PDIODE          2
#define DEFAULT_PGAIN           PGAIN_8X
#define DEFAULT_AGAIN           AGAIN_1X
#define DEFAULT_PILT            0       // Low proximity threshold
#define DEFAULT_PIHT            50      // High proximity threshold
#define DEFAULT_AILT            0xFFFF  // Force interrupt for calibration
#define DEFAULT_AIHT            0
#define DEFAULT_PERS            0x22    // 2 consecutive prox or ALS for int.

/* ALS coefficients */
#define DF                      52
#define GA                      0.49
#define ALS_B                       1.862
#define ALS_C                       0.746
#define ALS_D                       1.291

/* State definitions */
enum {
  NOTAVAILABLE_STATE,
  NEAR_STATE,
  FAR_STATE,
  ALL_STATE
};

#ifdef _AVR_IO_H_
// Do not use this alias as it's deprecated
#define NA_STATE NOTAVAILABLE_STATE
#endif

/* APDS9930 Class */
class APDS9930 {
  public:

    /* Initialization methods */
    APDS9930();
    ~APDS9930();
    bool init();
    uint8_t getMode();
    bool setMode(uint8_t mode, uint8_t enable);

    /* Turn the APDS-9930 on and off */
    bool enablePower();
    bool disablePower();

    /* Enable or disable specific sensors */
    bool enableLightSensor(bool interrupts = false);
    bool disableLightSensor();
    bool enableProximitySensor(bool interrupts = false);
    bool disableProximitySensor();

    /* LED drive strength control */
    uint8_t getLEDDrive();
    bool setLEDDrive(uint8_t drive);
    // uint8_t getGestureLEDDrive();
    // bool setGestureLEDDrive(uint8_t drive);

    /* Gain control */
    uint8_t getAmbientLightGain();
    bool setAmbientLightGain(uint8_t gain);
    uint8_t getProximityGain();
    bool setProximityGain(uint8_t gain);
    bool setProximityDiode(uint8_t drive);
    uint8_t getProximityDiode();


    /* Get and set light interrupt thresholds */
    bool getLightIntLowThreshold(uint16_t &threshold);
    bool setLightIntLowThreshold(uint16_t threshold);
    bool getLightIntHighThreshold(uint16_t &threshold);
    bool setLightIntHighThreshold(uint16_t threshold);

    /* Get and set interrupt enables */
    uint8_t getAmbientLightIntEnable();
    bool setAmbientLightIntEnable(uint8_t enable);
    uint8_t getProximityIntEnable();
    bool setProximityIntEnable(uint8_t enable);

    /* Clear interrupts */
    bool clearAmbientLightInt();
    bool clearProximityInt();
    bool clearAllInts();

    /* Proximity methods */
    bool readProximity(uint16_t &val);

    /* Ambient light methods */
    bool readAmbientLightLux(float &val);
    bool readAmbientLightLux(unsigned long &val);
    float floatAmbientToLux(uint16_t Ch0, uint16_t Ch1);
    unsigned long ulongAmbientToLux(uint16_t Ch0, uint16_t Ch1);
    bool readCh0Light(uint16_t &val);
    bool readCh1Light(uint16_t &val);

    //private:

    /* Proximity Interrupt Threshold */
    uint16_t getProximityIntLowThreshold();
    bool setProximityIntLowThreshold(uint16_t threshold);
    uint16_t getProximityIntHighThreshold();
    bool setProximityIntHighThreshold(uint16_t threshold);

    /* Raw I2C Commands */
    bool wireWriteByte(uint8_t val);
    bool wireWriteDataByte(uint8_t reg, uint8_t val);
    bool wireWriteDataBlock(uint8_t reg, uint8_t *val, unsigned int len);
    bool wireReadDataByte(uint8_t reg, uint8_t &val);
    int wireReadDataBlock(uint8_t reg, uint8_t *val, unsigned int len);
};

#endif

1、靠近亮灯、距离保持约10cm常亮,远离延时熄灭

ProximityInterrupt.ino

/****************************************************************
ProximityInterrupt.ino
APDS-9930 Ambient light and proximity sensor
Davide Depau
December 11, 2015
https://github.com/Davideddu/APDS9930

Shawn Hymel @ SparkFun Electronics
October 24, 2014
https://github.com/sparkfun/APDS-9930_RGB_and_Gesture_Sensor

Tests the proximity interrupt abilities of the APDS-9930.
Configures the APDS-9930 over I2C and waits for an external
interrupt based on high or low proximity conditions. Move your
hand near the sensor and watch the LED on pin 13.

Hardware Connections:

IMPORTANT: The APDS-9930 can only accept 3.3V!
 
 Arduino Pin  APDS-9930 Board  Function
 
 3.3V         VCC              Power
 GND          GND              Ground
 A4           SDA              I2C Data
 A5           SCL              I2C Clock
 2            INT              Interrupt
 10           -                LED

Resources:
Include Wire.h and APDS9930.h

Development environment specifics:
Written in Arduino 1.6.5
Tested with Arduino Uno and Mega

This code is beerware; if you see me (or any other SparkFun 
employee) at the local, and you've found our code helpful, please
buy us a round!

Distributed as-is; no warranty is given.
****************************************************************/

#define DUMP_REGS

#include <Wire.h>
#include "APDS9930.h"

// Pins
#define APDS9930_INT    2  // Needs to be an interrupt pin
#define LED_PIN         10 // LED for showing interrupt

// Constants
#define PROX_INT_HIGH   600 // Proximity level for interrupt
#define PROX_INT_LOW    0  // No far interrupt

// 亮灯延时
#define LIGHT_TIME 5000

// Global variables
APDS9930 apds = APDS9930();
uint16_t proximity_data = 0;
volatile bool isr_flag = false;

void setup() {
  // Set LED as output
  pinMode(LED_PIN, OUTPUT);
  pinMode(APDS9930_INT, INPUT);
  
  // Initialize Serial port
  Serial.begin(9600);
  Serial.println();
  Serial.println(F("------------------------------"));
  Serial.println(F("APDS-9930 - ProximityInterrupt"));
  Serial.println(F("------------------------------"));
  
  // Initialize interrupt service routine
  attachInterrupt(0, interruptRoutine, FALLING);
  
  // Initialize APDS-9930 (configure I2C and initial values)
  if ( apds.init() ) {
    Serial.println(F("APDS-9930 initialization complete"));
  } else {
    Serial.println(F("Something went wrong during APDS-9930 init!"));
  }
  
  // Adjust the Proximity sensor gain
  if ( !apds.setProximityGain(PGAIN_2X) ) {
    Serial.println(F("Something went wrong trying to set PGAIN"));
  }
  
  // Set proximity interrupt thresholds
  if ( !apds.setProximityIntLowThreshold(PROX_INT_LOW) ) {
    Serial.println(F("Error writing low threshold"));
  }
  if ( !apds.setProximityIntHighThreshold(PROX_INT_HIGH) ) {
    Serial.println(F("Error writing high threshold"));
  }
  
  // Start running the APDS-9930 proximity sensor (interrupts)
  if ( apds.enableProximitySensor(true) ) {
    Serial.println(F("Proximity sensor is now running"));
  } else {
    Serial.println(F("Something went wrong during sensor init!"));
  }

#ifdef DUMP_REGS
  /* Register dump */
  uint8_t reg;
  uint8_t val;

  for(reg = 0x00; reg <= 0x19; reg++) {
    if( (reg != 0x10) && \
        (reg != 0x11) )
    {
      apds.wireReadDataByte(reg, val);
      Serial.print(reg, HEX);
      Serial.print(": 0x");
      Serial.println(val, HEX);
    }
  }
  apds.wireReadDataByte(0x1E, val);
  Serial.print(0x1E, HEX);
  Serial.print(": 0x");
  Serial.println(val, HEX);
#endif

}

/*
 * 主循环
 * 功能介绍:当有物体靠近传感器约10cm的位置时,触发中断,点亮LED LIGHT_TIME毫秒,持续触发则常亮,无则灭灯。 
 * 说明:通过修改 宏定义 LIGHT_TIME调节延时,LED负极接在数字10口(正极 3.3V供电)
*/
void loop() {  
  // If interrupt occurs, print out the proximity level
  if ( isr_flag ) {
    // Read proximity level and print it out
    if ( !apds.readProximity(proximity_data) ) {
      Serial.println("Error reading proximity value");
    } else {
      Serial.print("Proximity detected! Level: ");
      Serial.println(proximity_data);
    }
    
    // Reset flag and clear APDS-9930 interrupt (IMPORTANT!)
    isr_flag = false;
    if ( !apds.clearProximityInt() ) {
      Serial.println("Error clearing interrupt");
    }

    // 点亮和延时放在清除中断后面,可以避免连续中断之间的LED闪烁问题
    digitalWrite(LED_PIN, LOW);
    delay(LIGHT_TIME);
  }
  else {
    // 无中断则熄灭LED
    digitalWrite(LED_PIN, HIGH);
  }
}

void interruptRoutine() {
  isr_flag = true;
}

2、点亮/熄灭LED,延时期间操作不响应

ProximityInterrupt.ino

/****************************************************************
ProximityInterrupt.ino
APDS-9930 Ambient light and proximity sensor
Davide Depau
December 11, 2015
https://github.com/Davideddu/APDS9930

Shawn Hymel @ SparkFun Electronics
October 24, 2014
https://github.com/sparkfun/APDS-9930_RGB_and_Gesture_Sensor

Tests the proximity interrupt abilities of the APDS-9930.
Configures the APDS-9930 over I2C and waits for an external
interrupt based on high or low proximity conditions. Move your
hand near the sensor and watch the LED on pin 13.

Hardware Connections:

IMPORTANT: The APDS-9930 can only accept 3.3V!
 
 Arduino Pin  APDS-9930 Board  Function
 
 3.3V         VCC              Power
 GND          GND              Ground
 A4           SDA              I2C Data
 A5           SCL              I2C Clock
 2            INT              Interrupt
 10           -                LED

Resources:
Include Wire.h and APDS9930.h

Development environment specifics:
Written in Arduino 1.6.5
Tested with Arduino Uno and Mega

This code is beerware; if you see me (or any other SparkFun 
employee) at the local, and you've found our code helpful, please
buy us a round!

Distributed as-is; no warranty is given.
****************************************************************/

#define DUMP_REGS

#include <Wire.h>
#include "APDS9930.h"

// Pins
#define APDS9930_INT    2  // Needs to be an interrupt pin
#define LED_PIN         10 // LED for showing interrupt

// Constants
#define PROX_INT_HIGH   600 // Proximity level for interrupt
#define PROX_INT_LOW    0  // No far interrupt

// 亮灯延时
#define LIGHT_TIME 5000
// 响应延时
#define RESPONSE_TIME 2000

// Global variables
APDS9930 apds = APDS9930();
uint16_t proximity_data = 0;
volatile bool isr_flag = false;

void setup() {
  // Set LED as output
  pinMode(LED_PIN, OUTPUT);
  pinMode(APDS9930_INT, INPUT);

  // 先熄灭LED
  digitalWrite(LED_PIN, HIGH);
  
  // Initialize Serial port
  Serial.begin(9600);
  Serial.println();
  Serial.println(F("------------------------------"));
  Serial.println(F("APDS-9930 - ProximityInterrupt"));
  Serial.println(F("------------------------------"));
  
  // Initialize interrupt service routine
  attachInterrupt(0, interruptRoutine, FALLING);
  
  // Initialize APDS-9930 (configure I2C and initial values)
  if ( apds.init() ) {
    Serial.println(F("APDS-9930 initialization complete"));
  } else {
    Serial.println(F("Something went wrong during APDS-9930 init!"));
  }
  
  // Adjust the Proximity sensor gain
  if ( !apds.setProximityGain(PGAIN_2X) ) {
    Serial.println(F("Something went wrong trying to set PGAIN"));
  }
  
  // Set proximity interrupt thresholds
  if ( !apds.setProximityIntLowThreshold(PROX_INT_LOW) ) {
    Serial.println(F("Error writing low threshold"));
  }
  if ( !apds.setProximityIntHighThreshold(PROX_INT_HIGH) ) {
    Serial.println(F("Error writing high threshold"));
  }
  
  // Start running the APDS-9930 proximity sensor (interrupts)
  if ( apds.enableProximitySensor(true) ) {
    Serial.println(F("Proximity sensor is now running"));
  } else {
    Serial.println(F("Something went wrong during sensor init!"));
  }

#ifdef DUMP_REGS
  /* Register dump */
  uint8_t reg;
  uint8_t val;

  for(reg = 0x00; reg <= 0x19; reg++) {
    if( (reg != 0x10) && \
        (reg != 0x11) )
    {
      apds.wireReadDataByte(reg, val);
      Serial.print(reg, HEX);
      Serial.print(": 0x");
      Serial.println(val, HEX);
    }
  }
  apds.wireReadDataByte(0x1E, val);
  Serial.print(0x1E, HEX);
  Serial.print(": 0x");
  Serial.println(val, HEX);
#endif

}

/*
 * 主循环
 * 功能介绍:当有物体靠近传感器约10cm的位置时,触发中断,点亮/熄灭LED,延时RESPONSE_TIME毫秒,延时期间操作不响应。 
 * 说明:通过修改 宏定义 RESPONSE_TIME调节延时响应,LED负极接在数字10口(正极 3.3V供电)
*/
void loop() {
  // 临时变量
  uint8_t temp = 0;
  
  // If interrupt occurs, print out the proximity level
  if ( isr_flag ) {
    // Read proximity level and print it out
    if ( !apds.readProximity(proximity_data) ) {
      Serial.println("Error reading proximity value");
    } else {
      Serial.print("Proximity detected! Level: ");
      Serial.println(proximity_data);
    }

    // 读取LED_PIN电平,反转电平
    temp = digitalRead(LED_PIN);
    if(temp == 0) digitalWrite(LED_PIN, HIGH);
    else digitalWrite(LED_PIN, LOW);
    delay(RESPONSE_TIME);
    
    // Reset flag and clear APDS-9930 interrupt (IMPORTANT!)
    isr_flag = false;
    if ( !apds.clearProximityInt() ) {
      Serial.println("Error clearing interrupt");
    }
  }
}

void interruptRoutine() {
  isr_flag = true;
}

3、挥手点亮/熄灭LED,悬停进行非无极pwm调光

ProximityInterrupt.ino

/****************************************************************
ProximityInterrupt.ino
APDS-9930 Ambient light and proximity sensor
Davide Depau
December 11, 2015
https://github.com/Davideddu/APDS9930

Shawn Hymel @ SparkFun Electronics
October 24, 2014
https://github.com/sparkfun/APDS-9930_RGB_and_Gesture_Sensor

Tests the proximity interrupt abilities of the APDS-9930.
Configures the APDS-9930 over I2C and waits for an external
interrupt based on high or low proximity conditions. Move your
hand near the sensor and watch the LED on pin 13.

Hardware Connections:

IMPORTANT: The APDS-9930 can only accept 3.3V!
 
 Arduino Pin  APDS-9930 Board  Function
 
 3.3V         VCC              Power
 GND          GND              Ground
 A4           SDA              I2C Data
 A5           SCL              I2C Clock
 2            INT              Interrupt
 10           -                LED

Resources:
Include Wire.h and APDS9930.h

Development environment specifics:
Written in Arduino 1.6.5
Tested with Arduino Uno and Mega

This code is beerware; if you see me (or any other SparkFun 
employee) at the local, and you've found our code helpful, please
buy us a round!

Distributed as-is; no warranty is given.
****************************************************************/

#define DUMP_REGS

#include <Wire.h>
#include "APDS9930.h"

// Pins
#define APDS9930_INT    2  // Needs to be an interrupt pin
#define LED_PIN         10 // LED for showing interrupt

// Constants
#define PROX_INT_HIGH   600 // Proximity level for interrupt
#define PROX_INT_LOW    0  // No far interrupt

// 亮灯延时
#define LIGHT_TIME 5000
// 响应延时
#define RESPONSE_TIME 300
// pwm每次变动的值
#define PWM_CHANGE_VAL 32

// Global variables
APDS9930 apds = APDS9930();
uint16_t proximity_data = 0;
volatile bool isr_flag = false;

// 中断计数
uint8_t interrupt_num = 0;
// 循环计数
uint8_t loop_num = 0;
// 0为开关模式 1为pwm调光模式
uint8_t mode = 0;
// pwm值
uint8_t pwm_val = 255;
// LED亮标志位 0灭 1亮
uint8_t led_on_flag = 0;

void setup() {
  // Set LED as output
  pinMode(LED_PIN, OUTPUT);
  pinMode(APDS9930_INT, INPUT);
  
  // Initialize Serial port
  Serial.begin(9600);
  Serial.println();
  Serial.println(F("------------------------------"));
  Serial.println(F("APDS-9930 - ProximityInterrupt"));
  Serial.println(F("------------------------------"));
  
  // Initialize interrupt service routine
  attachInterrupt(0, interruptRoutine, FALLING);
  
  // Initialize APDS-9930 (configure I2C and initial values)
  if ( apds.init() ) {
    Serial.println(F("APDS-9930 initialization complete"));
  } else {
    Serial.println(F("Something went wrong during APDS-9930 init!"));
  }
  
  // Adjust the Proximity sensor gain
  if ( !apds.setProximityGain(PGAIN_2X) ) {
    Serial.println(F("Something went wrong trying to set PGAIN"));
  }
  
  // Set proximity interrupt thresholds
  if ( !apds.setProximityIntLowThreshold(PROX_INT_LOW) ) {
    Serial.println(F("Error writing low threshold"));
  }
  if ( !apds.setProximityIntHighThreshold(PROX_INT_HIGH) ) {
    Serial.println(F("Error writing high threshold"));
  }
  
  // Start running the APDS-9930 proximity sensor (interrupts)
  if ( apds.enableProximitySensor(true) ) {
    Serial.println(F("Proximity sensor is now running"));
  } else {
    Serial.println(F("Something went wrong during sensor init!"));
  }

#ifdef DUMP_REGS
  /* Register dump */
  uint8_t reg;
  uint8_t val;

  for(reg = 0x00; reg <= 0x19; reg++) {
    if( (reg != 0x10) && \
        (reg != 0x11) )
    {
      apds.wireReadDataByte(reg, val);
      Serial.print(reg, HEX);
      Serial.print(": 0x");
      Serial.println(val, HEX);
    }
  }
  apds.wireReadDataByte(0x1E, val);
  Serial.print(0x1E, HEX);
  Serial.print(": 0x");
  Serial.println(val, HEX);
#endif

  // 先熄灭LED
  digitalWrite(LED_PIN, HIGH);
}

/*
 * 主循环
 * 功能介绍:
 *    当有物体靠近传感器约10cm的位置时,可以触发中断。
 *    如果4*RESPONSE_TIME毫秒内 没有触发4次中断,即4*RESPONSE_TIME毫秒内,划过传感区域,则为开关模式,会进行LED的亮灭操作(亮到设定的pwm_val)
 *    如果4*RESPONSE_TIME毫秒内 触发了4次中断,即4*RESPONSE_TIME毫秒以上,物体一直停留在传感区域内,则为pwm调光模式,会进行LED的pwm非无极调光(每次在当前基础上增加PWM_CHANGE_VAL)
 *    如果在pwm调光模式下,物体移出了传感区域,则会结束pwm值的调节。若下次继续快划,则进行开关,若继续悬停,则继续调光。
 *    单位延时RESPONSE_TIME毫秒,延时期间操作不响应。 
 * 说明:
 *    通过修改 宏定义 RESPONSE_TIME调节延时响应,若想增加调光速率,可减小此值。
 *    通过修改 宏定义 PWM_CHANGE_VAL,调节单次pwm调光的大小,范围1-255。若想要更细致的调光,可减小此值。
 *    LED负极接在数字10口(正极 3.3V供电)
*/
void loop() {
  // 临时变量
  uint8_t temp = 0;

  loop_num++;
  
  // If interrupt occurs, print out the proximity level
  if ( isr_flag ) {
    interrupt_num++;
    
    // Read proximity level and print it out
    if ( !apds.readProximity(proximity_data) ) {
      Serial.println("Error reading proximity value");
    } else {
      Serial.print("Proximity detected! Level: ");
      Serial.println(proximity_data);
    }
    
    // Reset flag and clear APDS-9930 interrupt (IMPORTANT!)
    isr_flag = false;
    if ( !apds.clearProximityInt() ) {
      Serial.println("Error clearing interrupt");
    }

    delay(RESPONSE_TIME);
  } else {
    delay(RESPONSE_TIME);
  }

  // 4次循环即 4*RESPONSE_TIME毫秒
  if(4 == loop_num) {
    // Serial.println("loop_num == 4");
    loop_num = 0;
    // 触发中断数小于4,认为是划过,非悬停状态。
    if(interrupt_num < 4 && interrupt_num > 0) {
      Serial.println("interrupt_num < 4 && interrupt_num > 0");
      // 如果是开关模式
      if(mode == 0) {
        // 读取LED_PIN电平
        temp = digitalRead(LED_PIN);
        Serial.print("temp:");
        Serial.println(temp);
        // temp>0 为 熄灭 或 pwm<255亮灯 状态
        if(temp > 0) {
          // pwm==255则点亮LED
          if(pwm_val == 255) {
            analogWrite(LED_PIN, 0);
            led_on_flag = 1;
          }
          // pwm!=255
          else {
            // 如果灯是熄灭状态,点亮至之前设定的pwm_val
            if(led_on_flag == 0) {
              analogWrite(LED_PIN, pwm_val);
              led_on_flag = 1;
            }
            // 如果灯是点亮状态,则熄灭
            else {
              analogWrite(LED_PIN, 255);
              led_on_flag = 0;
            }
          }
        } else {
          // 熄灭LED
          analogWrite(LED_PIN, 255);
          led_on_flag = 0;
        }
      } else {
        // 切换为开关模式
        mode = 0;
      }

      Serial.print("pwm_val:");
      Serial.println(pwm_val);
    } else if(interrupt_num == 4) {
      Serial.println("interrupt_num == 4");
      // 切换为pwm调光模式
      mode = 1;
      pwm_val += PWM_CHANGE_VAL;
      // 0到255之间的PWM频率值
      analogWrite(LED_PIN, pwm_val);
      if(pwm_val == 255) led_on_flag = 0;
      else led_on_flag = 1;

      Serial.print("pwm_val:");
      Serial.println(pwm_val);
    }

    // 清零
    loop_num = 0;
    interrupt_num = 0;
  }
}

void interruptRoutine() {
  isr_flag = true;
}

参考图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

以下是使用Arduino Uno和Apds9960来控制WS2812B灯条的程序: ``` #include <Wire.h> #include <Adafruit_Gesture.h> #include <Adafruit_APDS9960.h> #include <Adafruit_NeoPixel.h> #define PIN 6 #define NUMPIXELS 60 Adafruit_APDS9960 apds; Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); void setup() { Serial.begin(9600); while (!Serial) { delay(100); } if (!apds.begin()) { Serial.println("Failed to initialize APDS9960 sensor."); while (1); } if (!pixels.begin()) { Serial.println("Failed to initialize NeoPixel strip."); while (1); } pixels.clear(); pixels.show(); } void loop() { uint8_t gesture = apds.readGesture(); if (gesture == APDS9960_DOWN) { pixels.setPixelColor(0, pixels.Color(255, 0, 0)); pixels.show(); } else if (gesture == APDS9960_UP) { pixels.setPixelColor(0, pixels.Color(0, 255, 0)); pixels.show(); } else if (gesture == APDS9960_LEFT) { pixels.setPixelColor(0, pixels.Color(0, 0, 255)); pixels.show(); } else if (gesture == APDS9960_RIGHT) { pixels.setPixelColor(0, pixels.Color(255, 255, 0)); pixels.show(); } } ``` 说明: 1. 引入必要的库文件:Wire.h、Adafruit_Gesture.h、Adafruit_APDS9960.h、Adafruit_NeoPixel.h。 2. 定义灯条的引脚号和像素数量。 3. 创建Adafruit_APDS9960和Adafruit_NeoPixel对象。 4. 在setup函数中,初始化APDS9960和NeoPixel灯条,并清空灯条。 5. 在loop函数中,读取手势,根据手势设置灯条的颜色。 需要注意的是,APDS9960与Arduino连接需要使用I2C协议,因此需要将APDS9960的SDA和SCL引脚连接到Arduino的对应引脚(一般是A4和A5)。同时,WS2812B灯条的引脚需要连接到Arduino的数字引脚。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Love丶伊卡洛斯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值