CayenneVCNL4000.h 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. /*
  2. The MIT License(MIT)
  3. Cayenne Arduino Client Library
  4. Copyright © 2016 myDevices
  5. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
  6. documentation files(the "Software"), to deal in the Software without restriction, including without limitation
  7. the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software,
  8. and to permit persons to whom the Software is furnished to do so, subject to the following conditions :
  9. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
  10. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  11. WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR
  12. COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  13. ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  14. This software uses open source blynk-library - see blynk-library/LICENSE
  15. This class adapted from Adafruit VCNL400 example sketch https://github.com/adafruit/VCNL4000/blob/master/vcnl4000.pde
  16. */
  17. #ifndef _CAYENNEVCNL4000_h
  18. #define _CAYENNEVCNL4000_h
  19. #include <Wire.h>
  20. #include <Arduino.h>
  21. // commands and constants
  22. #define VCNL4000_ADDRESS 0x13
  23. #define VCNL4000_COMMAND 0x80
  24. #define VCNL4000_PRODUCTID 0x81
  25. #define VCNL4000_IRLED 0x83
  26. #define VCNL4000_AMBIENTPARAMETER 0x84
  27. #define VCNL4000_AMBIENTDATA 0x85
  28. #define VCNL4000_PROXIMITYDATA 0x87
  29. #define VCNL4000_SIGNALFREQ 0x89
  30. #define VCNL4000_PROXINITYADJUST 0x8A
  31. #define VCNL4000_3M125 0
  32. #define VCNL4000_1M5625 1
  33. #define VCNL4000_781K25 2
  34. #define VCNL4000_390K625 3
  35. #define VCNL4000_MEASUREAMBIENT 0x10
  36. #define VCNL4000_MEASUREPROXIMITY 0x08
  37. #define VCNL4000_AMBIENTREADY 0x40
  38. #define VCNL4000_PROXIMITYREADY 0x20
  39. #define CALIBRATION_CYCLES 5
  40. #define MEASUREMENT_CYCLES 10
  41. #define THRESHOLD 25
  42. #define NO_PROXIMITY -1
  43. #define TIMEOUT 2000
  44. class VCNL4000
  45. {
  46. public:
  47. bool begin() {
  48. Wire.begin();
  49. uint8_t rev = read8(VCNL4000_PRODUCTID);
  50. if ((rev & 0xF0) != 0x10) {
  51. return false;
  52. }
  53. write8(VCNL4000_IRLED, 20); // Set IR current
  54. write8(VCNL4000_SIGNALFREQ, VCNL4000_781K25); // Set proximity signal frequency
  55. write8(VCNL4000_PROXINITYADJUST, 0x81); // Set proximity timing
  56. calibrate();
  57. return true;
  58. }
  59. float getLux() {
  60. return (readAmbient() + 3) * 0.25;
  61. }
  62. int getMillimeters() {
  63. unsigned int success = 0;
  64. unsigned int fail = 0;
  65. unsigned int proximitySum = 0;
  66. while ((fail < MEASUREMENT_CYCLES) && (success < MEASUREMENT_CYCLES)) {
  67. uint16_t realCount = readProximity() - _offset;
  68. if (realCount > _threshold) {
  69. success++;
  70. proximitySum += realCount;
  71. }
  72. else {
  73. fail++;
  74. }
  75. }
  76. if (fail == MEASUREMENT_CYCLES) {
  77. return NO_PROXIMITY;
  78. }
  79. else {
  80. return calculateMillimeters(proximitySum / MEASUREMENT_CYCLES);
  81. }
  82. }
  83. uint16_t readProximity() {
  84. write8(VCNL4000_COMMAND, VCNL4000_MEASUREPROXIMITY);
  85. while (1) {
  86. uint8_t result = read8(VCNL4000_COMMAND);
  87. if (result & VCNL4000_PROXIMITYREADY) {
  88. return read16(VCNL4000_PROXIMITYDATA);
  89. }
  90. delay(1);
  91. }
  92. }
  93. uint16_t readAmbient() {
  94. write8(VCNL4000_COMMAND, VCNL4000_MEASUREAMBIENT);
  95. while (1) {
  96. uint8_t result = read8(VCNL4000_COMMAND);
  97. if (result & VCNL4000_AMBIENTREADY) {
  98. return read16(VCNL4000_AMBIENTDATA);
  99. }
  100. delay(1);
  101. }
  102. }
  103. private:
  104. void calibrate() {
  105. for (int i = 0; i < CALIBRATION_CYCLES; ++i) {
  106. _offset += readProximity();
  107. }
  108. _offset = _offset / CALIBRATION_CYCLES;
  109. }
  110. uint16_t calculateMillimeters(uint16_t proximityCounts) {
  111. //According to chip spec the proximity counts are strong non-linear with distance and cannot be calculated
  112. //with a direct formula. From experience found on web this chip is generally not suited for really exact
  113. //distance calculations. This is a rough distance estimation lookup table for now. Maybe someone can
  114. //provide a more exact approximation in the future.
  115. unsigned int estimatedDistance = 100;
  116. if (proximityCounts >= 10000) {
  117. estimatedDistance = 0;
  118. }
  119. else if (proximityCounts >= 3000) {
  120. estimatedDistance = 5;
  121. }
  122. else if (proximityCounts >= 900) {
  123. estimatedDistance = 10;
  124. }
  125. else if (proximityCounts >= 300) {
  126. estimatedDistance = 20;
  127. }
  128. else if (proximityCounts >= 150) {
  129. estimatedDistance = 30;
  130. }
  131. else if (proximityCounts >= 75) {
  132. estimatedDistance = 40;
  133. }
  134. else if (proximityCounts >= 50) {
  135. estimatedDistance = 50;
  136. }
  137. else if (proximityCounts >= 25) {
  138. estimatedDistance = 70;
  139. }
  140. return estimatedDistance;
  141. }
  142. // Read 1 byte from the VCNL4000 at 'address'
  143. uint8_t read8(uint8_t address)
  144. {
  145. uint8_t data;
  146. Wire.beginTransmission(VCNL4000_ADDRESS);
  147. #if ARDUINO >= 100
  148. Wire.write(address);
  149. #else
  150. Wire.send(address);
  151. #endif
  152. Wire.endTransmission();
  153. delayMicroseconds(170); // delay required
  154. Wire.requestFrom(VCNL4000_ADDRESS, 1);
  155. unsigned int start = millis();
  156. while (!Wire.available() && (millis() - start < TIMEOUT));
  157. #if ARDUINO >= 100
  158. return Wire.read();
  159. #else
  160. return Wire.receive();
  161. #endif
  162. }
  163. // Read 2 byte from the VCNL4000 at 'address'
  164. uint16_t read16(uint8_t address)
  165. {
  166. uint16_t data;
  167. Wire.beginTransmission(VCNL4000_ADDRESS);
  168. #if ARDUINO >= 100
  169. Wire.write(address);
  170. #else
  171. Wire.send(address);
  172. #endif
  173. Wire.endTransmission();
  174. Wire.requestFrom(VCNL4000_ADDRESS, 2);
  175. unsigned int start = millis();
  176. while (!Wire.available() && (millis() - start < TIMEOUT));
  177. #if ARDUINO >= 100
  178. data = Wire.read();
  179. data <<= 8;
  180. start = millis();
  181. while (!Wire.available() && (millis() - start < TIMEOUT));
  182. data |= Wire.read();
  183. #else
  184. data = Wire.receive();
  185. data <<= 8;
  186. start = millis();
  187. while (!Wire.available() && (millis() - start < TIMEOUT));
  188. data |= Wire.receive();
  189. #endif
  190. return data;
  191. }
  192. // write 1 byte
  193. void write8(uint8_t address, uint8_t data)
  194. {
  195. Wire.beginTransmission(VCNL4000_ADDRESS);
  196. #if ARDUINO >= 100
  197. Wire.write(address);
  198. Wire.write(data);
  199. #else
  200. Wire.send(address);
  201. Wire.send(data);
  202. #endif
  203. Wire.endTransmission();
  204. }
  205. uint16_t _offset;
  206. uint16_t _threshold;
  207. };
  208. #endif