Seeed_LDC1612.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. /*
  2. Seeed_LDC1612.cpp
  3. Driver for DIGITAL I2C HUMIDITY AND TEMPERATURE SENSOR
  4. Copyright (c) 2018 Seeed Technology Co., Ltd.
  5. Website : www.seeed.cc
  6. Author : downey
  7. Create Time: June 2018
  8. Change Log :
  9. The MIT License (MIT)
  10. Permission is hereby granted, free of charge, to any person obtaining a copy
  11. of this software and associated documentation files (the "Software"), to deal
  12. in the Software without restriction, including without limitation the rights
  13. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  14. copies of the Software, and to permit persons to whom the Software is
  15. furnished to do so, subject to the following conditions:
  16. The above copyright notice and this permission notice shall be included in
  17. all copies or substantial portions of the Software.
  18. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24. THE SOFTWARE.
  25. */
  26. #include "Seeed_LDC1612.h"
  27. #include "math.h"
  28. /** @brief read sensor's information
  29. * */
  30. void LDC1612::read_sensor_infomation() {
  31. u16 value = 0;
  32. IIC_read_16bit(READ_MANUFACTURER_ID, &value);
  33. Serial.print("manufacturer id =0x");
  34. Serial.println(value, HEX);
  35. IIC_read_16bit(READ_DEVICE_ID, &value);
  36. Serial.print("DEVICE id =0x");
  37. Serial.println(value, HEX);
  38. return ;
  39. }
  40. /** @brief constructor,support set IIC addr,default iic addr is 0x2b.
  41. * */
  42. LDC1612::LDC1612(u8 IIC_ADDR) {
  43. set_iic_addr(IIC_ADDR);
  44. }
  45. /** @brief config sensor
  46. * */
  47. s32 LDC1612::init() {
  48. /*Start IIC communication!*/
  49. IIC_begin();
  50. /*reset sensor*/
  51. return 0;
  52. }
  53. s32 LDC1612::single_channel_config(u8 channel) {
  54. /*Set coil inductor parameter first.*/
  55. /*20 TURNS*/
  56. set_Rp(CHANNEL_0, 15.727);
  57. set_L(CHANNEL_0, 18.147);
  58. set_C(CHANNEL_0, 100);
  59. set_Q_factor(CHANNEL_0, 35.97);
  60. // /*25 TURNS*/
  61. // set_Rp(CHANNEL_0,24.9);
  62. // set_L(CHANNEL_0,53.95);
  63. // set_C(CHANNEL_0,100);
  64. // set_Q_factor(CHANNEL_0,32.57);
  65. /*36 TURNS,single layer*/
  66. // set_Rp(CHANNEL_0,28.18);
  67. // set_L(CHANNEL_0,18.56);
  68. // set_C(CHANNEL_0,100);
  69. // set_Q_factor(CHANNEL_0,43.25);
  70. /*40 TURNS*/
  71. // set_Rp(CHANNEL_0,57.46);
  72. // set_L(CHANNEL_0,85.44);
  73. // set_C(CHANNEL_0,100);
  74. // set_Q_factor(CHANNEL_0,40.7);
  75. if (set_FIN_FREF_DIV(CHANNEL_0)) {
  76. return -1;
  77. }
  78. set_LC_stabilize_time(CHANNEL_0);
  79. /*Set conversion interval time*/
  80. set_conversion_time(CHANNEL_0, 0x0546);
  81. /*Set driver current!*/
  82. set_driver_current(CHANNEL_0, 0xa000);
  83. /*single conversion*/
  84. set_mux_config(0x20c);
  85. /*start channel 0*/
  86. u16 config = 0x1601;
  87. select_channel_to_convert(CHANNEL_0, &config);
  88. set_sensor_config(config);
  89. return 0;
  90. }
  91. s32 LDC1612::LDC1612_mutiple_channel_config() {
  92. /*Set coil inductor parameter first.*/
  93. /*20 TURNS*/
  94. set_Rp(CHANNEL_0, 15.727);
  95. set_L(CHANNEL_0, 18.147);
  96. set_C(CHANNEL_0, 100);
  97. set_Q_factor(CHANNEL_0, 35.97);
  98. /*25 TURNS*/
  99. set_Rp(CHANNEL_1, 15.727);
  100. set_L(CHANNEL_1, 18.147);
  101. set_C(CHANNEL_1, 100);
  102. set_Q_factor(CHANNEL_1, 35.97);
  103. // /*36 TURNS single layer*/
  104. // set_Rp(CHANNEL_0,28.18);
  105. // set_L(CHANNEL_0,18.56);
  106. // set_C(CHANNEL_0,100);
  107. // set_Q_factor(CHANNEL_0,43.25);
  108. // /*40 TURNS*/
  109. // set_Rp(CHANNEL_1,57.46);
  110. // set_L(CHANNEL_1,85.44);
  111. // set_C(CHANNEL_1,100);
  112. // set_Q_factor(CHANNEL_0,40.7);
  113. if (set_FIN_FREF_DIV(CHANNEL_0)) {
  114. return -1;
  115. }
  116. set_FIN_FREF_DIV(CHANNEL_1);
  117. /* 16*38/Fref=30us ,wait 30us for LC sensor stabilize before initiation of a conversion.*/
  118. set_LC_stabilize_time(CHANNEL_0);
  119. set_LC_stabilize_time(CHANNEL_1);
  120. /*Set conversion interval time*/
  121. set_conversion_time(CHANNEL_0, 0x0546);
  122. set_conversion_time(CHANNEL_1, 0x0546);
  123. /*Set driver current!*/
  124. set_driver_current(CHANNEL_0, 0xa000);
  125. set_driver_current(CHANNEL_1, 0xa000);
  126. /*mutiple conversion*/
  127. set_mux_config(0x820c);
  128. //set_mux_config(0x20c);
  129. /*start channel 0*/
  130. set_sensor_config(0x1601);
  131. //u16 config=0x1601;
  132. //select_channel_to_convert(0,&config);
  133. return 0;
  134. }
  135. /** @brief parse the data which read from data register.
  136. @param channel LDC1612 has total two channels.
  137. @param raw_result the raw data which read from data register,it contains error codes and sensor value;
  138. * */
  139. s32 LDC1612::parse_result_data(u8 channel, u32 raw_result, u32* result) {
  140. u8 value = 0;
  141. *result = raw_result & 0x0fffffff;
  142. if (0xfffffff == *result) {
  143. Serial.println("can't detect coil Coil Inductance!!!");
  144. *result = 0;
  145. return -1;
  146. }
  147. // else if(0==*result)
  148. // {
  149. // Serial.println("result is none!!!");
  150. // }
  151. value = raw_result >> 24;
  152. if (value & 0x80) {
  153. Serial.print("channel ");
  154. Serial.print(channel);
  155. Serial.println(": ERR_UR-Under range error!!!");
  156. }
  157. if (value & 0x40) {
  158. Serial.print("channel ");
  159. Serial.print(channel);
  160. Serial.println(": ERR_OR-Over range error!!!");
  161. }
  162. if (value & 0x20) {
  163. Serial.print("channel ");
  164. Serial.print(channel);
  165. Serial.println(": ERR_WD-Watch dog timeout error!!!");
  166. }
  167. if (value & 0x10) {
  168. Serial.print("channel ");
  169. Serial.print(channel);
  170. Serial.println(": ERR_AE-error!!!");
  171. }
  172. return 0;
  173. }
  174. /** @brief read the raw channel result from register.
  175. @param channel LDC1612 has total two channels.
  176. @param result raw data
  177. * */
  178. s32 LDC1612::get_channel_result(u8 channel, u32* result) {
  179. u32 raw_value = 0;
  180. if (NULL == result) {
  181. return -1;
  182. }
  183. u16 value = 0;
  184. IIC_read_16bit(CONVERTION_RESULT_REG_START + channel * 2, &value);
  185. raw_value |= (u32)value << 16;
  186. IIC_read_16bit(CONVERTION_RESULT_REG_START + channel * 2 + 1, &value);
  187. raw_value |= (u32)value;
  188. parse_result_data(channel, raw_value, result);
  189. return 0;
  190. }
  191. /** @brief set conversion interval time.
  192. @param channel LDC1612 has total two channels.
  193. @param result The value to be set.
  194. * */
  195. s32 LDC1612::set_conversion_time(u8 channel, u16 value) {
  196. return IIC_write_16bit(SET_CONVERSION_TIME_REG_START + channel, value);
  197. }
  198. /** @brief set conversion offset.
  199. @param channel LDC1612 has total two channels.
  200. @param result The value to be set.
  201. * */
  202. s32 LDC1612::set_conversion_offset(u8 channel, u16 value) {
  203. return IIC_write_16bit(SET_CONVERSION_OFFSET_REG_START + channel, value);
  204. }
  205. /** @brief Before conversion,wait LC sensor stabilize for a short time.
  206. @param channel LDC1612 has total two channels.
  207. @param result The value to be set.
  208. * */
  209. s32 LDC1612::set_LC_stabilize_time(u8 channel) {
  210. u16 value = 0;
  211. value = 30;
  212. return IIC_write_16bit(SET_LC_STABILIZE_REG_START + channel, value);
  213. }
  214. /** @brief set input frequency divide and fref divide.
  215. @param channel LDC1612 has total two channels.
  216. @param FIN_DIV FIN input divide
  217. @param FREF_DIV fref,reference frequency of sensor.
  218. * */
  219. s32 LDC1612::set_FIN_FREF_DIV(u8 channel) {
  220. u16 value;
  221. u16 FIN_DIV, FREF_DIV;
  222. Fsensor[channel] = 1 / (2 * 3.14 * sqrt(inductance[channel] * capacitance[channel] * pow(10, -18))) * pow(10, -6);
  223. Serial.print("fsensor =");
  224. Serial.println(Fsensor[channel]);
  225. FIN_DIV = (u16)(Fsensor[channel] / 8.75 + 1);
  226. if (Fsensor[channel] * 4 < 40) {
  227. FREF_DIV = 2;
  228. Fref[channel] = 40 / 2;
  229. } else {
  230. FREF_DIV = 4;
  231. Fref[channel] = 40 / 4;
  232. }
  233. value = FIN_DIV << 12;
  234. value |= FREF_DIV;
  235. return IIC_write_16bit(SET_FREQ_REG_START + channel, value);
  236. }
  237. /** @brief Error output config.
  238. @param result The value to be set.
  239. * */
  240. s32 LDC1612::set_ERROR_CONFIG(u16 value) {
  241. return IIC_write_16bit(ERROR_CONFIG_REG, value);
  242. }
  243. /** @brief mux config.
  244. @param result The value to be set.
  245. * */
  246. s32 LDC1612::set_mux_config(u16 value) {
  247. return IIC_write_16bit(MUL_CONFIG_REG, value);
  248. }
  249. /** @brief reset sensor.
  250. * */
  251. s32 LDC1612::reset_sensor() {
  252. return IIC_write_16bit(SENSOR_RESET_REG, 0x8000);
  253. }
  254. /** @brief set drive current of sensor.
  255. @param result The value to be set.
  256. * */
  257. s32 LDC1612::set_driver_current(u8 channel, u16 value) {
  258. return IIC_write_16bit(SET_DRIVER_CURRENT_REG + channel, value);
  259. }
  260. /** @brief Main config part of sensor.Contains select channel、start conversion、sleep mode、sensor activation mode、INT pin disable ..
  261. @param result The value to be set.
  262. * */
  263. s32 LDC1612::set_sensor_config(u16 value) {
  264. return IIC_write_16bit(SENSOR_CONFIG_REG, value);
  265. }
  266. /** @brief select channel to convert
  267. * */
  268. void LDC1612::select_channel_to_convert(u8 channel, u16* value) {
  269. switch (channel) {
  270. case 0: *value &= 0x3fff;
  271. break;
  272. case 1: *value &= 0x7fff;
  273. *value |= 0x4000;
  274. break;
  275. case 2: *value &= 0xbfff;
  276. *value |= 0x8000;
  277. break;
  278. case 3: *value |= 0xc000;
  279. break;
  280. }
  281. }
  282. void LDC1612::set_Rp(u8 channel, float n_kom) {
  283. resistance[channel] = n_kom;
  284. }
  285. void LDC1612::set_L(u8 channel, float n_uh) {
  286. inductance[channel] = n_uh;
  287. }
  288. void LDC1612::set_C(u8 channel, float n_pf) {
  289. capacitance[channel] = n_pf;
  290. }
  291. void LDC1612::set_Q_factor(u8 channel, float q) {
  292. Q_factor[channel] = q;
  293. }
  294. const char* status_str[] = {"conversion under range error", "conversion over range error",
  295. "watch dog timeout error", "Amplitude High Error",
  296. "Amplitude Low Error", "Zero Count Error",
  297. "Data Ready", "unread conversion is present for channel 0",
  298. " unread conversion is present for Channel 1.",
  299. "unread conversion ispresent for Channel 2.",
  300. "unread conversion is present for Channel 3."
  301. };
  302. /** @brief parse sensor statu data.
  303. * */
  304. s32 LDC1612::sensor_status_parse(u16 value) {
  305. u16 section = 0;
  306. section = value >> 14;
  307. switch (section) {
  308. case 0: Serial.println("Channel 0 is source of flag or error.");
  309. break;
  310. case 1: Serial.println("Channel 1 is source of flag or error.");
  311. break;
  312. /*Only support LDC1614*/
  313. case 2: Serial.println("Channel 2 is source of flag or error.");
  314. break;
  315. case 3: Serial.println("Channel 3 is source of flag or error.");
  316. break;
  317. default:
  318. break;
  319. }
  320. for (u32 i = 0; i < 6; i++) {
  321. if (value & (u16)1 << (8 + i)) {
  322. Serial.println(status_str[6 - i]);
  323. }
  324. }
  325. if (value & (1 << 6)) {
  326. Serial.println(status_str[6]);
  327. }
  328. for (u32 i = 0; i < 4; i++) {
  329. if (value & (1 << i)) {
  330. Serial.println(status_str[10 - i]);
  331. }
  332. }
  333. return 0;
  334. }
  335. /** @brief get sensor status
  336. * */
  337. u32 LDC1612::get_sensor_status() {
  338. u16 value = 0;
  339. IIC_read_16bit(SENSOR_STATUS_REG, &value);
  340. // Serial.print("status =");
  341. // Serial.println(value,HEX);
  342. sensor_status_parse(value);
  343. return value;
  344. }
  345. /**********************************************************************************************************/
  346. /************************************************IIC PART************************************************/
  347. /**********************************************************************************************************/
  348. s32 LDC1612_IIC_OPRTS::IIC_write_byte(u8 reg, u8 byte) {
  349. Wire.beginTransmission(_IIC_ADDR);
  350. Wire.write(reg);
  351. Wire.write(byte);
  352. return Wire.endTransmission();
  353. }
  354. s32 LDC1612_IIC_OPRTS::IIC_write_16bit(u8 reg, u16 value) {
  355. Wire.beginTransmission(_IIC_ADDR);
  356. Wire.write(reg);
  357. Wire.write((u8)(value >> 8));
  358. Wire.write((u8)value);
  359. return Wire.endTransmission();
  360. }
  361. void LDC1612_IIC_OPRTS::IIC_read_byte(u8 reg, u8* byte) {
  362. Wire.beginTransmission(_IIC_ADDR);
  363. Wire.write(reg);
  364. Wire.endTransmission(false);
  365. Wire.requestFrom(_IIC_ADDR, (u8)1);
  366. while (1 != Wire.available());
  367. *byte = Wire.read();
  368. }
  369. void LDC1612_IIC_OPRTS::IIC_read_16bit(u8 start_reg, u16* value) {
  370. u8 val = 0;
  371. *value = 0;
  372. Wire.beginTransmission(_IIC_ADDR);
  373. Wire.write(start_reg);
  374. Wire.endTransmission(false);
  375. Wire.requestFrom(_IIC_ADDR, sizeof(u16));
  376. while (sizeof(u16) != Wire.available());
  377. val = Wire.read();
  378. *value |= (u16)val << 8;
  379. val = Wire.read();
  380. *value |= val;
  381. }
  382. void LDC1612_IIC_OPRTS::set_iic_addr(u8 IIC_ADDR) {
  383. _IIC_ADDR = IIC_ADDR;
  384. }