APDS-9960姿势传感器 STM32程序

技术设计 · 2017/12/10
← 返回技术文章

/** * @file SparkFun_APDS-9960.h * @brief Library fo...

/**

* @file SparkFun_APDS-9960.h

* @brief Library for the SparkFun APDS-9960 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-9960 to Arduino over I2C. The library

* relies on the Arduino Wire (I2C) library. to use the library, instantiate an

* APDS9960 object, call init(), and call the appropriate functions.

*/

#ifndef SparkFun_APDS9960_H

#define SparkFun_APDS9960_H

#include <stdbool.h>

#include "stm32f10x.h"

/* Debug */

#define DEBUG 0

/* APDS-9960 I2C address */

#define APDS9960_I2C_ADDR 0x39

/* Gesture parameters */

#define GESTURE_THRESHOLD_OUT 10

#define GESTURE_SENSITIVITY_1 50

#define GESTURE_SENSITIVITY_2 20

/* Error code for returned values */

#define ERROR 0xFF

/* Acceptable device IDs */

#define APDS9960_ID_1 0xAB

#define APDS9960_ID_2 0x9C

/* Misc parameters */

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

/* APDS-9960 register addresses */

#define APDS9960_ENABLE 0x80

#define APDS9960_ATIME 0x81

#define APDS9960_WTIME 0x83

#define APDS9960_AILTL 0x84

#define APDS9960_AILTH 0x85

#define APDS9960_AIHTL 0x86

#define APDS9960_AIHTH 0x87

#define APDS9960_PILT 0x89

#define APDS9960_PIHT 0x8B

#define APDS9960_PERS 0x8C

#define APDS9960_CONFIG1 0x8D

#define APDS9960_PPULSE 0x8E

#define APDS9960_CONTROL 0x8F

#define APDS9960_CONFIG2 0x90

#define APDS9960_ID 0x92

#define APDS9960_STATUS 0x93

#define APDS9960_CDATAL 0x94

#define APDS9960_CDATAH 0x95

#define APDS9960_RDATAL 0x96

#define APDS9960_RDATAH 0x97

#define APDS9960_GDATAL 0x98

#define APDS9960_GDATAH 0x99

#define APDS9960_BDATAL 0x9A

#define APDS9960_BDATAH 0x9B

#define APDS9960_PDATA 0x9C

#define APDS9960_POFFSET_UR 0x9D

#define APDS9960_POFFSET_DL 0x9E

#define APDS9960_CONFIG3 0x9F

#define APDS9960_GPENTH 0xA0

#define APDS9960_GEXTH 0xA1

#define APDS9960_GCONF1 0xA2

#define APDS9960_GCONF2 0xA3

#define APDS9960_GOFFSET_U 0xA4

#define APDS9960_GOFFSET_D 0xA5

#define APDS9960_GOFFSET_L 0xA7

#define APDS9960_GOFFSET_R 0xA9

#define APDS9960_GPULSE 0xA6

#define APDS9960_GCONF3 0xAA

#define APDS9960_GCONF4 0xAB

#define APDS9960_GFLVL 0xAE

#define APDS9960_GSTATUS 0xAF

#define APDS9960_IFORCE 0xE4

#define APDS9960_PICLEAR 0xE5

#define APDS9960_CICLEAR 0xE6

#define APDS9960_AICLEAR 0xE7

#define APDS9960_GFIFO_U 0xFC

#define APDS9960_GFIFO_D 0xFD

#define APDS9960_GFIFO_L 0xFE

#define APDS9960_GFIFO_R 0xFF

/* Bit fields */

#define APDS9960_PON 00000001

#define APDS9960_AEN 00000010

#define APDS9960_PEN 00000100

#define APDS9960_WEN 00001000

#define APSD9960_AIEN 00010000

#define APDS9960_PIEN 00100000

#define APDS9960_GEN 01000000

#define APDS9960_GVALID 00000001

/* 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 GESTURE 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_4X 1

#define AGAIN_16X 2

#define AGAIN_64X 3

/* Gesture Gain (GGAIN) values */

#define GGAIN_1X 0

#define GGAIN_2X 1

#define GGAIN_4X 2

#define GGAIN_8X 3

/* LED Boost values */

#define LED_BOOST_100 0

#define LED_BOOST_150 1

#define LED_BOOST_200 2

#define LED_BOOST_300 3

/* Gesture wait time values */

#define GWTIME_0MS 0

#define GWTIME_2_8MS 1

#define GWTIME_5_6MS 2

#define GWTIME_8_4MS 3

#define GWTIME_14_0MS 4

#define GWTIME_22_4MS 5

#define GWTIME_30_8MS 6

#define GWTIME_39_2MS 7

/* Default values */

#define DEFAULT_ATIME 219 // 103ms

#define DEFAULT_WTIME 246 // 27ms

#define DEFAULT_PROX_PPULSE 0x87 // 16us, 8 pulses

#define DEFAULT_GESTURE_PPULSE 0x89 // 16us, 10 pulses

#define DEFAULT_POFFSET_UR 0 // 0 offset

#define DEFAULT_POFFSET_DL 0 // 0 offset

#define DEFAULT_CONFIG1 0x60 // No 12x wait (WTIME) factor

#define DEFAULT_LDRIVE LED_DRIVE_100MA

#define DEFAULT_PGAIN PGAIN_4X

#define DEFAULT_AGAIN AGAIN_4X

#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 0x11 // 2 consecutive prox or ALS for int.

#define DEFAULT_CONFIG2 0x01 // No saturation interrupts or LED boost

#define DEFAULT_CONFIG3 0 // Enable all photodiodes, no SAI

#define DEFAULT_GPENTH 40 // Threshold for entering gesture mode

#define DEFAULT_GEXTH 30 // Threshold for exiting gesture mode

#define DEFAULT_GCONF1 0x40 // 4 gesture events for int., 1 for exit

#define DEFAULT_GGAIN GGAIN_4X

#define DEFAULT_GLDRIVE LED_DRIVE_100MA

#define DEFAULT_GWTIME GWTIME_2_8MS

#define DEFAULT_GOFFSET 0 // No offset scaling for gesture mode

#define DEFAULT_GPULSE 0xC9 // 32us, 10 pulses

#define DEFAULT_GCONF3 0 // All photodiodes active during gesture

#define DEFAULT_GIEN 0 // Disable gesture interrupts

/* Direction definitions */

enum {

DIR_NONE,

DIR_LEFT,

DIR_RIGHT,

DIR_UP,

DIR_DOWN,

DIR_NEAR,

DIR_FAR,

DIR_ALL

};

/* State definitions */

enum {

NA_STATE,

NEAR_STATE,

FAR_STATE,

ALL_STATE

};

/* APDS9960 */

/* Initialization methods */

void SparkFun_APDS9960(void);

bool SparkFun_APDS9960_init(void);

uint8_t getMode(void);

bool setMode(int8_t mode, uint8_t enable);

/* Turn the APDS-9960 on and off */

bool enablePower(void);

bool disablePower(void);

bool enableGestureSensor(bool interrupts);

/* LED drive strength control */

bool setGestureLEDDrive(uint8_t drive);

/* Gain control */

bool setGestureGain(uint8_t gain);

/* Get and set interrupt enables */

bool setGestureIntEnable(uint8_t enable);

/* Gesture methods */

bool isGestureAvailable(void);

int readGesture(void);

/* Gesture processing */

void resetGestureParameters(void);

bool processGestureData(void);

bool decodeGesture(void);

/* LED Boost Control */

bool setLEDBoost(uint8_t boost);

/* Gesture threshold control */

bool setGestureEnterThresh(uint8_t threshold);

bool setGestureExitThresh(uint8_t threshold);

/* Gesture LED, gain, and time control */

bool setGestureWaitTime(uint8_t time);

/* Gesture mode */

bool setGestureMode(uint8_t mode);

/* Raw I2C Commands */

bool wireWriteDataByte(uint8_t reg, uint8_t val);

bool wireReadDataByte(uint8_t reg, uint8_t *val);

int wireReadDataBlock(uint8_t reg, uint8_t *val, unsigned int len);

#endif

/**

* @file SparkFun_APDS-9960.cpp

* @brief Library for the SparkFun APDS-9960 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-9960 to Arduino over I2C. The library

* relies on the Arduino Wire (I2C) library. to use the library, instantiate an

* APDS9960 object, call init(), and call the appropriate functions.

*

* APDS-9960 current draw tests (default parameters):

* Off: 1mA

* Waiting for gesture: 14mA

* Gesture in progress: 35mA

*/

#include <math.h>

#include <stdbool.h>

#include "APDS_9960.h"

#include "delay.h"

#include "myiic.h"

#include "LED.h"

#include "usart.h"

extern int abs(int __x);

void Wire_begin_(void);

/* Container for gesture data */

typedef struct gesture_data_type {

uint8_t u_data[32];

uint8_t d_data[32];

uint8_t l_data[32];

uint8_t r_data[32];

uint8_t index;

uint8_t total_gestures;

uint8_t in_threshold;

uint8_t out_threshold;

} gesture_data_type;

/* Members */

gesture_data_type gesture_data_;

int gesture_ud_delta_;

int gesture_lr_delta_;

int gesture_ud_count_;

int gesture_lr_count_;

int gesture_near_count_;

int gesture_far_count_;

int gesture_state_;

int gesture_motion_;

/**

* @brief Constructor - Instantiates SparkFun_APDS9960 object

*/

void SparkFun_APDS9960(void)

{

gesture_ud_delta_ = 0;

gesture_lr_delta_ = 0;

gesture_ud_count_ = 0;

gesture_lr_count_ = 0;

gesture_near_count_ = 0;

gesture_far_count_ = 0;

gesture_state_ = 0;

gesture_motion_ = DIR_NONE;

}

/**

* @brief Configures I2C communications and initializes registers to defaults

*

* @return True if initialized successfully. False otherwise.

*/

bool SparkFun_APDS9960_init(void)

{

uint8_t id,*pid;

/* Initialize I2C */

Wire_begin_();

/* Read ID register and check against known values for APDS-9960 */

if( !wireReadDataByte(APDS9960_ID, pid) )

{

return false;

}

id=*pid;

if( !((id == APDS9960_ID_1 || id == APDS9960_ID_2)) )

{

return false;

}

/* Set ENABLE register to 0 (disable all features) */

if( !setMode(ALL, OFF) )

{

return false;

}

/* Set default values for gesture sense registers */

if( !setGestureEnterThresh(DEFAULT_GPENTH) ) {

return false;

}

if( !setGestureExitThresh(DEFAULT_GEXTH) ) {

return false;

}

if( !wireWriteDataByte(APDS9960_GCONF1, DEFAULT_GCONF1) ) {

return false;

}

if( !setGestureGain(DEFAULT_GGAIN) ) {

return false;

}

if( !setGestureLEDDrive(DEFAULT_GLDRIVE) ) {

return false;

}

if( !setGestureWaitTime(DEFAULT_GWTIME) ) {

return false;

}

if( !wireWriteDataByte(APDS9960_GOFFSET_U, DEFAULT_GOFFSET) ) {

return false;

}

if( !wireWriteDataByte(APDS9960_GOFFSET_D, DEFAULT_GOFFSET) ) {

return false;

}

if( !wireWriteDataByte(APDS9960_GOFFSET_L, DEFAULT_GOFFSET) ) {

return false;

}

if( !wireWriteDataByte(APDS9960_GOFFSET_R, DEFAULT_GOFFSET) ) {

return false;

}

if( !wireWriteDataByte(APDS9960_GPULSE, DEFAULT_GPULSE) ) {

return false;

}

if( !wireWriteDataByte(APDS9960_GCONF3, DEFAULT_GCONF3) ) {

return false;

}

if( !setGestureIntEnable(DEFAULT_GIEN) ) {

return false;

}

return true;

}

/*******************************************************************************

* Public methods for controlling the APDS-9960

******************************************************************************/

/**

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

*

* @return Contents of the ENABLE register. 0xFF if error.

*/

uint8_t getMode(void)

{

uint8_t enable_value;

/* Read current ENABLE register */

if( !wireReadDataByte(APDS9960_ENABLE, &enable_value) ) {

return ERROR;

}

return enable_value;

}

/**

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

*

* @param[in] mode which feature to enable

* @param[in] enable ON (1) or OFF (0)

* @return True if operation success. False otherwise.

*/

bool setMode(int8_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(APDS9960_ENABLE, reg_val) ) {

return false;

}

return true;

}

/**

* @brief Starts the gesture recognition engine on the APDS-9960

*

* @param[in] interrupts true to enable hardware external interrupt on gesture

* @return True if engine enabled correctly. False on error.

*/

bool enableGestureSensor(bool interrupts)

{

/* Enable gesture mode

Set ENABLE to 0 (power off)

Set WTIME to 0xFF

Set AUX to LED_BOOST_300

Enable PON, WEN, PEN, GEN in ENABLE

*/

//interrupts = true;

resetGestureParameters();

if( !wireWriteDataByte(APDS9960_WTIME, 0xFF) ) {

return false;

}

if( !wireWriteDataByte(APDS9960_PPULSE, DEFAULT_GESTURE_PPULSE) ) {

return false;

}

if( !setLEDBoost(LED_BOOST_300) ) {

return false;

}

if( interrupts ) {

if( !setGestureIntEnable(1) ) {

return false;

}

} else {

if( !setGestureIntEnable(0) ) {

return false;

}

}

if( !setGestureMode(1) ) {

return false;

}

if( !enablePower() ){

return false;

}

if( !setMode(WAIT, 1) ) {

return false;

}

if( !setMode(PROXIMITY, 1) ) {

return false;

}

if( !setMode(GESTURE, 1) ) {

return false;

}

return true;

}

/**

* @brief Determines if there is a gesture available for reading

*

* @return True if gesture available. False otherwise.

*/

bool isGestureAvailable(void)

{

uint8_t val;

/* Read value from GSTATUS register */

if( !wireReadDataByte(APDS9960_GSTATUS, &val) )

{

return ERROR;

}

/* Shift and mask out GVALID bit */

val&=APDS9960_GVALID;

/* Return true/false based on GVALID bit */

if( val == 1)

{

return true;

}

else

{

return false;

}

}

/**

* @brief Processes a gesture event and returns best guessed gesture

*

* @return Number corresponding to gesture. -1 on error.

*/

int readGesture(void)

{

uint8_t fifo_level = 0;

int8_t bytes_read = 0;

uint8_t fifo_data[128];

uint8_t gstatus;

int motion;

int i;

/* Make sure that power and gesture is on and data is valid */

if(!isGestureAvailable()||!(getMode()&01000001) ) {

return DIR_NONE;

}

/* Keep looping as long as gesture data is valid */

while(1) {

/* Wait some time to collect next batch of FIFO data */

delay_ms(FIFO_PAUSE_TIME);

/* Get the contents of the STATUS register. Is data still valid? */

if( !wireReadDataByte(APDS9960_GSTATUS, &gstatus) ) {

return ERROR;

}

/* If we have valid data, read in FIFO */

if((gstatus & APDS9960_GVALID)==APDS9960_GVALID)

{

/* Read the current FIFO level */

if( !wireReadDataByte(APDS9960_GFLVL, &fifo_level) )

{

return ERROR;

}

/* If there's stuff in the FIFO, read it into our data block */

if( fifo_level > 0) {

bytes_read = wireReadDataBlock( APDS9960_GFIFO_U,

(uint8_t*)fifo_data,

(fifo_level * 4) );

if(bytes_read==-1) {

return ERROR;

}

/* If at least 1 set of data, sort the data into U/D/L/R */

if( bytes_read >= 4 ) {

for( i = 0; i < bytes_read; i += 4 ) {

gesture_data_.u_data[gesture_data_.index] = \

fifo_data[i + 0];

gesture_data_.d_data[gesture_data_.index] = \

fifo_data[i + 1];

gesture_data_.l_data[gesture_data_.index] = \

fifo_data[i + 2];

gesture_data_.r_data[gesture_data_.index] = \

fifo_data[i + 3];

gesture_data_.index++;

gesture_data_.total_gestures++;

}

/* Filter and process gesture data. Decode near/far state */

if( processGestureData() ) {

if( decodeGesture() ) {

//***TODO: U-Turn Gestures

}

}

/* Reset data */

gesture_data_.index = 0;

gesture_data_.total_gestures = 0;

}

}

} else

{

/* Determine best guessed gesture and clean up */

delay_ms(FIFO_PAUSE_TIME);

decodeGesture();

motion = gesture_motion_;

resetGestureParameters();

return motion;

}

}

}

/**

* Turn the APDS-9960 on

*

* @return True if operation successful. False otherwise.

*/

bool enablePower(void)

{

if( !setMode(POWER, 1) ) {

return false;

}

return true;

}

/**

* Turn the APDS-9960 off

*

* @return True if operation successful. False otherwise.

*/

bool disablePower(void)

{

if( !setMode(POWER, 0) ) {

return false;

}

return true;

}

/*******************************************************************************

* High-level gesture controls

******************************************************************************/

/**

* @brief Resets all the parameters in the gesture data member

*/

void resetGestureParameters(void)

{

gesture_data_.index = 0;

gesture_data_.total_gestures = 0;

gesture_ud_delta_ = 0;

gesture_lr_delta_ = 0;

gesture_ud_count_ = 0;

gesture_lr_count_ = 0;

gesture_near_count_ = 0;

gesture_far_count_ = 0;

gesture_state_ = 0;

gesture_motion_ = DIR_NONE;

}

/**

* @brief Processes the raw gesture data to determine swipe direction

*

* @return True if near or far state seen. False otherwise.

*/

bool processGestureData(void)

{

uint8_t u_first = 0;

uint8_t d_first = 0;

uint8_t l_first = 0;

uint8_t r_first = 0;

uint8_t u_last = 0;

uint8_t d_last = 0;

uint8_t l_last = 0;

uint8_t r_last = 0;

int ud_ratio_first;

int lr_ratio_first;

int ud_ratio_last;

int lr_ratio_last;

int ud_delta;

int lr_delta;

int i;

/* If we have less than 4 total gestures, that's not enough */

if( gesture_data_.total_gestures <= 4 ) {

return false;

}

/* Check to make sure our data isn't out of bounds */

if( (gesture_data_.total_gestures <= 32) && \

(gesture_data_.total_gestures > 0) ) {

/* Find the first value in U/D/L/R above the threshold */

for( i = 0; i < gesture_data_.total_gestures; i++ ) {

if( (gesture_data_.u_data[i] > GESTURE_THRESHOLD_OUT) &&

(gesture_data_.d_data[i] > GESTURE_THRESHOLD_OUT) &&

(gesture_data_.l_data[i] > GESTURE_THRESHOLD_OUT) &&

(gesture_data_.r_data[i] > GESTURE_THRESHOLD_OUT) ) {

u_first = gesture_data_.u_data[i];

d_first = gesture_data_.d_data[i];

l_first = gesture_data_.l_data[i];

r_first = gesture_data_.r_data[i];

break;

}

}

/* If one of the _first values is 0, then there is no good data */

if( (u_first == 0) || (d_first == 0) || \

(l_first == 0) || (r_first == 0) ) {

return false;

}

/* Find the last value in U/D/L/R above the threshold */

for( i = gesture_data_.total_gestures - 1; i >= 0; i-- ) {

if( (gesture_data_.u_data[i] > GESTURE_THRESHOLD_OUT) &&

(gesture_data_.d_data[i] > GESTURE_THRESHOLD_OUT) &&

(gesture_data_.l_data[i] > GESTURE_THRESHOLD_OUT) &&

(gesture_data_.r_data[i] > GESTURE_THRESHOLD_OUT) ) {

u_last = gesture_data_.u_data[i];

d_last = gesture_data_.d_data[i];

l_last = gesture_data_.l_data[i];

r_last = gesture_data_.r_data[i];

break;

}

}

}

/* Calculate the first vs. last ratio of up/down and left/right */

ud_ratio_first = ((u_first - d_first) * 100) / (u_first + d_first);

lr_ratio_first = ((l_first - r_first) * 100) / (l_first + r_first);

ud_ratio_last = ((u_last - d_last) * 100) / (u_last + d_last);

lr_ratio_last = ((l_last - r_last) * 100) / (l_last + r_last);

/* Determine the difference between the first and last ratios */

ud_delta = ud_ratio_last - ud_ratio_first;

lr_delta = lr_ratio_last - lr_ratio_first;

/* Accumulate the UD and LR delta values */

gesture_ud_delta_ += ud_delta;

gesture_lr_delta_ += lr_delta;

/* Determine U/D gesture */

if( gesture_ud_delta_ >= GESTURE_SENSITIVITY_1 ) {

gesture_ud_count_ = 1;

} else if( gesture_ud_delta_ <= -GESTURE_SENSITIVITY_1 ) {

gesture_ud_count_ = -1;

} else {

gesture_ud_count_ = 0;

}

/* Determine L/R gesture */

if( gesture_lr_delta_ >= GESTURE_SENSITIVITY_1 ) {

gesture_lr_count_ = 1;

} else if( gesture_lr_delta_ <= -GESTURE_SENSITIVITY_1 ) {

gesture_lr_count_ = -1;

} else {

gesture_lr_count_ = 0;

}

/* Determine Near/Far gesture */

if( (gesture_ud_count_ == 0) && (gesture_lr_count_ == 0) ) {

if( (abs(ud_delta) < GESTURE_SENSITIVITY_2) && (abs(lr_delta) < GESTURE_SENSITIVITY_2) )

{

if( (ud_delta == 0) && (lr_delta == 0) ) {

gesture_near_count_++;

} else if( (ud_delta != 0) || (lr_delta != 0) ) {

gesture_far_count_++;

}

if( (gesture_near_count_ >= 10) && (gesture_far_count_ >= 2) ) {

if( (ud_delta == 0) && (lr_delta == 0) ) {

gesture_state_ = NEAR_STATE;

} else if( (ud_delta != 0) && (lr_delta != 0) ) {

gesture_state_ = FAR_STATE;

}

return true;

}

}

} else {

if( (abs((int)ud_delta) < GESTURE_SENSITIVITY_2) && (abs((int)lr_delta) < GESTURE_SENSITIVITY_2) ) {

if( (ud_delta == 0) && (lr_delta == 0) ) {

gesture_near_count_++;

}

if( gesture_near_count_ >= 10 ) {

gesture_ud_count_ = 0;

gesture_lr_count_ = 0;

gesture_ud_delta_ = 0;

gesture_lr_delta_ = 0;

}

}

}

return false;

}

/**

* @brief Determines swipe direction or near/far state

*

* @return True if near/far event. False otherwise.

*/

bool decodeGesture(void)

{

/* Return if near or far event is detected */

if( gesture_state_ == NEAR_STATE ) {

gesture_motion_ = DIR_NEAR;

return true;

} else if ( gesture_state_ == FAR_STATE ) {

gesture_motion_ = DIR_FAR;

return true;

}

/* Determine swipe direction */

if( (gesture_ud_count_ == -1) && (gesture_lr_count_ == 0) ) {

gesture_motion_ = DIR_UP;

} else if( (gesture_ud_count_ == 1) && (gesture_lr_count_ == 0) ) {

gesture_motion_ = DIR_DOWN;

} else if( (gesture_ud_count_ == 0) && (gesture_lr_count_ == 1) ) {

gesture_motion_ = DIR_RIGHT;

} else if( (gesture_ud_count_ == 0) && (gesture_lr_count_ == -1) ) {

gesture_motion_ = DIR_LEFT;

} else if( (gesture_ud_count_ == -1) && (gesture_lr_count_ == 1) ) {

if( abs(gesture_ud_delta_) > abs(gesture_lr_delta_) ) {

gesture_motion_ = DIR_UP;

} else {

gesture_motion_ = DIR_RIGHT;

}

} else if( (gesture_ud_count_ == 1) && (gesture_lr_count_ == -1) ) {

if( abs(gesture_ud_delta_) > abs(gesture_lr_delta_) ) {

gesture_motion_ = DIR_DOWN;

} else {

gesture_motion_ = DIR_LEFT;

}

} else if( (gesture_ud_count_ == -1) && (gesture_lr_count_ == -1) ) {

if( abs(gesture_ud_delta_) > abs(gesture_lr_delta_) ) {

gesture_motion_ = DIR_UP;

} else {

gesture_motion_ = DIR_LEFT;

}

} else if( (gesture_ud_count_ == 1) && (gesture_lr_count_ == 1) ) {

if( abs(gesture_ud_delta_) > abs(gesture_lr_delta_) ) {

gesture_motion_ = DIR_DOWN;

} else {

gesture_motion_ = DIR_RIGHT;

}

} else {

return false;

}

return true;

}

/**

* @brief Sets the LED current boost value

*

* Value Boost Current

* 0 100%

* 1 150%

* 2 200%

* 3 300%

*

* @param[in] drive the value (0-3) for current boost (100-300%)

* @return True if operation successful. False otherwise.

*/

bool setLEDBoost(uint8_t boost)

{

uint8_t val;

/* Read value from CONFIG2 register */

if( !wireReadDataByte(APDS9960_CONFIG2, &val) ) {

return false;

}

/* Set bits in register to given value */

boost &= 00000011;

boost = boost << 4;

val &= 11001111;

val |= boost;

/* Write register value back into CONFIG2 register */

if( !wireWriteDataByte(APDS9960_CONFIG2, val) ) {

return false;

}

return true;

}

/**

* @brief Sets the entry proximity threshold for gesture sensing

*

* @param[in] threshold proximity value needed to start gesture mode

* @return True if operation successful. False otherwise.

*/

bool setGestureEnterThresh(uint8_t threshold)

{

if( !wireWriteDataByte(APDS9960_GPENTH, threshold) ) {

return false;

}

return true;

}

/**

* @brief Sets the exit proximity threshold for gesture sensing

*

* @param[in] threshold proximity value needed to end gesture mode

* @return True if operation successful. False otherwise.

*/

bool setGestureExitThresh(uint8_t threshold)

{

if( !wireWriteDataByte(APDS9960_GEXTH, threshold) ) {

return false;

}

return true;

}

/**

* @brief Sets the gain of the photodiode during gesture mode

*

* Value Gain

* 0 1x

* 1 2x

* 2 4x

* 3 8x

*

* @param[in] gain the value for the photodiode gain

* @return True if operation successful. False otherwise.

*/

bool setGestureGain(uint8_t gain)

{

uint8_t val;

/* Read value from GCONF2 register */

if( !wireReadDataByte(APDS9960_GCONF2, &val) ) {

return false;

}

/* Set bits in register to given value */

gain &= 00000011;

gain = gain << 5;

val &= 10011111;

val |= gain;

/* Write register value back into GCONF2 register */

if( !wireWriteDataByte(APDS9960_GCONF2, val) ) {

return false;

}

return true;

}

/**

* @brief Sets the LED drive current during gesture mode

*

* Value LED Current

* 0 100 mA

* 1 50 mA

* 2 25 mA

* 3 12.5 mA

*

* @param[in] drive the value for the LED drive current

* @return True if operation successful. False otherwise.

*/

bool setGestureLEDDrive(uint8_t drive)

{

uint8_t val;

/* Read value from GCONF2 register */

if( !wireReadDataByte(APDS9960_GCONF2, &val) ) {

return false;

}

/* Set bits in register to given value */

drive &= 00000011;

drive = drive << 3;

val &= 11100111;

val |= drive;

/* Write register value back into GCONF2 register */

if( !wireWriteDataByte(APDS9960_GCONF2, val) ) {

return false;

}

return true;

}

/**

* @brief Sets the time in low power mode between gesture detections

*

* Value Wait time

* 0 0 ms

* 1 2.8 ms

* 2 5.6 ms

* 3 8.4 ms

* 4 14.0 ms

* 5 22.4 ms

* 6 30.8 ms

* 7 39.2 ms

*

* @param[in] the value for the wait time

* @return True if operation successful. False otherwise.

*/

bool setGestureWaitTime(uint8_t time)

{

uint8_t val;

/* Read value from GCONF2 register */

if( !wireReadDataByte(APDS9960_GCONF2, &val)){

return false;

}

/* Set bits in register to given value */

time &= 00000111;

val &= 11111000;

val |= time;

/* Write register value back into GCONF2 register */

if( !wireWriteDataByte(APDS9960_GCONF2, val) ) {

return false;

}

return true;

}

/**

* @brief Turns gesture-related interrupts on or off

*

* @param[in] enable 1 to enable interrupts, 0 to turn them off

* @return True if operation successful. False otherwise.

*/

bool setGestureIntEnable(uint8_t enable)

{

uint8_t val;

/* Read value from GCONF4 register */

if( !wireReadDataByte(APDS9960_GCONF4, &val) ) {

return false;

}

/* Set bits in register to given value */

enable &= 00000001;

enable = enable << 1;

val &= 11111101;

val |= enable;

/* Write register value back into GCONF4 register */

if( !wireWriteDataByte(APDS9960_GCONF4, val) ) {

return false;

}

return true;

}

/**

* @brief Tells the state machine to either enter or exit gesture state machine

*

* @param[in] mode 1 to enter gesture state machine, 0 to exit.

* @return True if operation successful. False otherwise.

*/

bool setGestureMode(uint8_t mode)

{

uint8_t val;

/* Read value from GCONF4 register */

if( !wireReadDataByte(APDS9960_GCONF4, &val) ) {

return false;

}

/* Set bits in register to given value */

mode &= 00000001;

val &= 11111110;

val |= mode;

/* Write register value back into GCONF4 register */

if( !wireWriteDataByte(APDS9960_GCONF4, val) ) {

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 wireWriteDataByte(uint8_t reg, uint8_t val)

{

IIC_Start();

IIC_Send_Byte((APDS9960_I2C_ADDR<<1)|0);//发送器件地址+写命令

if(IIC_Wait_Ack()) //等待应答

{

IIC_Stop();

return false;

}

IIC_Send_Byte(reg); //写寄存器地址

IIC_Wait_Ack(); //等待应答

IIC_Send_Byte(val);//发送数据

if(IIC_Wait_Ack()) //等待ACK

{

IIC_Stop();

return false;

}

IIC_Stop();

return true;

// IIC_Start();

// IIC_Send_Byte((APDS9960_I2C_ADDR<<1)|0x00);//发送器件地址+写命令

// IIC_Wait_Ack(); //等待应答

// IIC_Send_Byte(reg); //写寄存器地址

// IIC_Wait_Ack(); //等待应答

// IIC_Send_Byte(val);//发送数据

// IIC_Wait_Ack(); //等待应答

// IIC_Stop();

//

// 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 wireReadDataByte(uint8_t reg,uint8_t *val)

{

IIC_Start();

IIC_Send_Byte((APDS9960_I2C_ADDR<<1)|0X00);//发送器件地址+写命令

IIC_Wait_Ack(); //等待应答

IIC_Send_Byte(reg); //写寄存器地址

IIC_Wait_Ack(); //等待应答

IIC_Start();

IIC_Send_Byte((APDS9960_I2C_ADDR<<1)|0x01);//发送器件地址+读命令

IIC_Wait_Ack(); //等待应答

*val=IIC_Read_Byte(0);//读取数据,发送nACK

IIC_Stop(); //产生一个停止条件

return true;

// IIC_Start();

// IIC_Send_Byte((APDS9960_I2C_ADDR<<1)|0);//发送器件地址+写命令

// if(IIC_Wait_Ack()) //等待ACK

// {

// IIC_Stop();

// return false;

// } //等待应答

// IIC_Send_Byte(reg); //写寄存器地址

// if(IIC_Wait_Ack()) //等待ACK

// {

// IIC_Stop();

// return false;

// } //等待应答

// IIC_Start();

// IIC_Send_Byte((APDS9960_I2C_ADDR<<1)|1);//发送器件地址+读命令

// if(IIC_Wait_Ack()) //等待ACK

// {

// IIC_Stop();

// return false;

// } //等待应答

// val=IIC_Read_Byte(0);//读取数据,发送nACK

// IIC_Stop(); //产生一个停止条件

// 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 wireReadDataBlock( uint8_t reg,uint8_t *val, unsigned int len)

{

unsigned char i = 0;

IIC_Start();

IIC_Send_Byte((APDS9960_I2C_ADDR<<1)|0);//发送器件地址+写命令

if(IIC_Wait_Ack()) //等待应答

{

IIC_Stop();

return -1;

}

IIC_Send_Byte(reg); //写寄存器地址

IIC_Wait_Ack(); //等待应答

IIC_Start();

IIC_Send_Byte((APDS9960_I2C_ADDR<<1)|1);//发送器件地址+读命令

IIC_Wait_Ack(); //等待应答

while(len)

{

// if(i >= len) //不能加,否则收不到数据

// {

// return -1;

// }

if(len==1) val[i]=IIC_Read_Byte(0);//读数据,发送nACK

else val[i]=IIC_Read_Byte(1); //读数据,发送ACK

i++;

len--;

}

IIC_Stop(); //产生一个停止条件

return i;

}

void Wire_begin_(void)

{

IIC_Init();

}