目录
前言
开发板: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;
}
参考图