sht20.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. /*
  2. * Copyright (c) 2006-2018, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2018-08-08 Ernest Chen the first version
  9. */
  10. #include <rthw.h>
  11. #include <rtthread.h>
  12. #include <rtdevice.h>
  13. #include <string.h>
  14. #define DBG_ENABLE
  15. #define DBG_SECTION_NAME "sht20"
  16. #define DBG_LEVEL DBG_LOG
  17. #define DBG_COLOR
  18. #include <rtdbg.h>
  19. #include "sht20.h"
  20. #ifdef PKG_USING_SHT2X
  21. /*sht20 registers define */
  22. #define TRIG_TEMP_MEASUREMENT_HM 0xE3 // trigger temperature measurement on hold master
  23. #define TRIG_HUMI_MEASUREMENT_HM 0xE5 // trigger humidity measurement on hold master
  24. #define TRIG_TEMP_MEASUREMENT_POLL 0xF3 // trigger temperature measurement without hold master
  25. #define TRIG_HUMI_MEASUREMENT_POLL 0xF5 // trigger humidity measurement without hold master
  26. #define USER_REG_W 0xE6 // write user register
  27. #define USER_REG_R 0xE7 // read user register
  28. #define SOFT_RESET 0xFE
  29. #define SHT20_RES_12_14BIT 0x00 // RH=12bit, T=14bit default
  30. #define SHT20_RES_8_12BIT 0x01 // RH= 8bit, T=12bit
  31. #define SHT20_RES_10_13BIT 0x80 // RH=10bit, T=13bit
  32. #define SHT20_RES_11_11BIT 0x81 // RH=11bit, T=11bit
  33. #define SHT20_RES_MASK 0x81 // Mask for res. bits (7,0) in user reg.
  34. #define SHT20_HEATER_ON 0x04 // heater on
  35. #define SHT20_HEATER_OFF 0x00 // heater off
  36. #define SHT20_HEATER_MASK 0x04 // Mask for Heater bit(2) in user reg.
  37. #define SHT20_BATTERY_HIGH 0x00 // higher than 2.25
  38. #define SHT20_BATTERY_LOW 0x40 // lower than 2.25
  39. #define SHT20_BATTERY_MASK 0x40 // Mask for batter bit(6) in user reg.
  40. #define SHT20_ADDR 0x40
  41. static rt_err_t write_reg(struct rt_i2c_bus_device *bus, rt_uint8_t reg, rt_uint8_t data)
  42. {
  43. rt_uint8_t buf[2];
  44. buf[0] = reg;
  45. buf[1] = data;
  46. if (rt_i2c_master_send(bus, SHT20_ADDR, 0, buf, 2) == 2)
  47. return RT_EOK;
  48. else
  49. return -RT_ERROR;
  50. }
  51. static rt_err_t read_regs(struct rt_i2c_bus_device *bus, rt_uint8_t reg, rt_uint8_t len, rt_uint8_t *buf)
  52. {
  53. struct rt_i2c_msg msgs[2];
  54. msgs[0].addr = SHT20_ADDR;
  55. msgs[0].flags = RT_I2C_WR;
  56. msgs[0].buf = &reg;
  57. msgs[0].len = 1;
  58. msgs[1].addr = SHT20_ADDR;
  59. msgs[1].flags = RT_I2C_RD;
  60. msgs[1].buf = buf;
  61. msgs[1].len = len;
  62. if (rt_i2c_transfer(bus, msgs, 2) == 2)
  63. {
  64. return RT_EOK;
  65. }
  66. else
  67. {
  68. return -RT_ERROR;
  69. }
  70. }
  71. static rt_err_t write_cmd(struct rt_i2c_bus_device *bus, rt_uint8_t cmd)
  72. {
  73. struct rt_i2c_msg msgs;
  74. msgs.addr = SHT20_ADDR;
  75. msgs.flags = RT_I2C_WR;
  76. msgs.buf = &cmd;
  77. msgs.len = 1;
  78. if (rt_i2c_transfer(bus, &msgs, 1) == 1)
  79. return RT_EOK;
  80. else
  81. return -RT_ERROR;
  82. }
  83. static float read_hw_humidity(sht20_device_t dev)
  84. {
  85. rt_uint8_t temp[2];
  86. float current_humi = 0.0; //The data is error with missing measurement.
  87. rt_err_t result;
  88. RT_ASSERT(dev);
  89. result = rt_mutex_take(dev->lock, RT_WAITING_FOREVER);
  90. if (result == RT_EOK)
  91. {
  92. read_regs(dev->i2c, TRIG_HUMI_MEASUREMENT_HM, 2, temp);
  93. current_humi = -6 + (temp[1] | temp[0] << 8) * 125.0 / (1 << 16); //sensor humidity convert to reality
  94. }
  95. else
  96. {
  97. LOG_E("The sht20 could not respond relative humidity measurement at this time. Please try again");
  98. }
  99. rt_mutex_release(dev->lock);
  100. return current_humi;
  101. }
  102. static float read_hw_temperature(sht20_device_t dev)
  103. {
  104. rt_uint8_t temp[2];
  105. float current_temp = -46.85; //The data is error with missing measurement.
  106. rt_err_t result;
  107. RT_ASSERT(dev);
  108. result = rt_mutex_take(dev->lock, RT_WAITING_FOREVER);
  109. if (result == RT_EOK)
  110. {
  111. read_regs(dev->i2c, TRIG_TEMP_MEASUREMENT_HM, 2, temp);
  112. current_temp = -46.85 + (temp[1] | temp[0] << 8) * 175.72 / (1 << 16); //sensor temperature convert to reality
  113. }
  114. else
  115. {
  116. LOG_E("The sht20 could not respond temperature measurement at this time. Please try again");
  117. }
  118. rt_mutex_release(dev->lock);
  119. return current_temp;
  120. }
  121. #ifdef SHT20_USING_SOFT_FILTER
  122. static void average_measurement(sht20_device_t dev, filter_data_t *filter)
  123. {
  124. rt_uint32_t i;
  125. float sum = 0;
  126. rt_uint32_t temp;
  127. rt_err_t result;
  128. RT_ASSERT(dev);
  129. result = rt_mutex_take(dev->lock, RT_WAITING_FOREVER);
  130. if (result == RT_EOK)
  131. {
  132. if (filter->is_full)
  133. {
  134. temp = SHT20_AVERAGE_TIMES;
  135. }
  136. else
  137. {
  138. temp = filter->index + 1;
  139. }
  140. for (i = 0; i < temp; i++)
  141. {
  142. sum += filter->buf[i];
  143. }
  144. filter->average = sum / temp;
  145. }
  146. else
  147. {
  148. LOG_E("The software failed to average at this time, please try again");
  149. }
  150. rt_mutex_release(dev->lock);
  151. }
  152. static void sht20_filter_entry(void *device)
  153. {
  154. RT_ASSERT(device);
  155. sht20_device_t dev = (sht20_device_t)device;
  156. while (1)
  157. {
  158. if (dev->temp_filter.index >= SHT20_AVERAGE_TIMES)
  159. {
  160. if (dev->temp_filter.is_full != RT_TRUE)
  161. {
  162. dev->temp_filter.is_full = RT_TRUE;
  163. }
  164. dev->temp_filter.index = 0;
  165. }
  166. if (dev->humi_filter.index >= SHT20_AVERAGE_TIMES)
  167. {
  168. if (dev->humi_filter.is_full != RT_TRUE)
  169. {
  170. dev->humi_filter.is_full = RT_TRUE;
  171. }
  172. dev->humi_filter.index = 0;
  173. }
  174. dev->temp_filter.buf[dev->temp_filter.index] = read_hw_temperature(dev);
  175. dev->humi_filter.buf[dev->humi_filter.index] = read_hw_humidity(dev);
  176. rt_thread_delay(rt_tick_from_millisecond(dev->period));
  177. dev->temp_filter.index++;
  178. dev->humi_filter.index++;
  179. }
  180. }
  181. #endif /* SHT20_USING_SOFT_FILTER */
  182. /**
  183. * This function resets all parameter with default
  184. *
  185. * @param dev the pointer of device driver structure
  186. *
  187. * @return the softreset status,RT_EOK reprensents setting successfully.
  188. */
  189. rt_err_t sht20_softreset(sht20_device_t dev)
  190. {
  191. RT_ASSERT(dev);
  192. write_cmd(dev->i2c, SOFT_RESET);
  193. return 0;
  194. }
  195. /**
  196. * This function reads temperature by sht20 sensor measurement
  197. *
  198. * @param dev the pointer of device driver structure
  199. *
  200. * @return the relative temperature converted to float data.
  201. */
  202. float sht20_read_temperature(sht20_device_t dev)
  203. {
  204. #ifdef SHT20_USING_SOFT_FILTER
  205. average_measurement(dev, &dev->temp_filter);
  206. return dev->temp_filter.average;
  207. #else
  208. return read_hw_temperature(dev);
  209. #endif /* SHT20_USING_SOFT_FILTER */
  210. }
  211. /**
  212. * This function reads relative humidity by sht20 sensor measurement
  213. *
  214. * @param dev the pointer of device driver structure
  215. *
  216. * @return the relative humidity converted to float data.
  217. */
  218. float sht20_read_humidity(sht20_device_t dev)
  219. {
  220. #ifdef SHT20_USING_SOFT_FILTER
  221. average_measurement(dev, &dev->humi_filter);
  222. return dev->humi_filter.average;
  223. #else
  224. return read_hw_humidity(dev);
  225. #endif /* SHT20_USING_SOFT_FILTER */
  226. }
  227. /**
  228. * This function initializes sht20 registered device driver
  229. *
  230. * @param dev the name of sht20 device
  231. *
  232. * @return the sht20 device.
  233. */
  234. sht20_device_t sht20_init(const char *i2c_bus_name)
  235. {
  236. sht20_device_t dev;
  237. RT_ASSERT(i2c_bus_name);
  238. dev = rt_calloc(1, sizeof(struct sht20_device));
  239. if (dev == RT_NULL)
  240. {
  241. LOG_E("Can't allocate memory for sht20 device on '%s' ", i2c_bus_name);
  242. rt_free(dev);
  243. return RT_NULL;
  244. }
  245. dev->i2c = rt_i2c_bus_device_find(i2c_bus_name);
  246. if (dev->i2c == RT_NULL)
  247. {
  248. LOG_E("Can't find sht20 device on '%s' ", i2c_bus_name);
  249. rt_free(dev);
  250. return RT_NULL;
  251. }
  252. dev->lock = rt_mutex_create("mutex_sht20", RT_IPC_FLAG_FIFO);
  253. if (dev->lock == RT_NULL)
  254. {
  255. LOG_E("Can't create mutex for sht20 device on '%s' ", i2c_bus_name);
  256. rt_free(dev);
  257. return RT_NULL;
  258. }
  259. #ifdef SHT20_USING_SOFT_FILTER
  260. dev->period = SHT20_SAMPLE_PERIOD;
  261. dev->thread = rt_thread_create("sht20", sht20_filter_entry, (void *)dev, 1024, 15, 10);
  262. if (dev->thread != RT_NULL)
  263. {
  264. rt_thread_startup(dev->thread);
  265. }
  266. else
  267. {
  268. LOG_E("Can't start filtering function for sht20 device on '%s' ", i2c_bus_name);
  269. rt_mutex_delete(dev->lock);
  270. rt_free(dev);
  271. }
  272. #endif /* SHT20_USING_SOFT_FILTER */
  273. return dev;
  274. }
  275. /**
  276. * This function releases memory and deletes mutex lock
  277. *
  278. * @param dev the pointer of device driver structure
  279. */
  280. void sht20_deinit(sht20_device_t dev)
  281. {
  282. RT_ASSERT(dev);
  283. rt_mutex_delete(dev->lock);
  284. #ifdef SHT20_USING_SOFT_FILTER
  285. rt_thread_delete(dev->thread);
  286. #endif
  287. rt_free(dev);
  288. }
  289. /**
  290. * This function sets parameter of sht20 sensor
  291. *
  292. * @param dev the pointer of device driver structure
  293. * @param type the parameter type of device
  294. * @param value the pointer value of type
  295. *
  296. * @return the setting parameter status,RT_EOK reprensents setting successfully.
  297. */
  298. rt_err_t sht20_set_param(sht20_device_t dev, sht20_param_type_t type, rt_uint8_t value)
  299. {
  300. RT_ASSERT(dev);
  301. switch (type)
  302. {
  303. case SHT20_PARAM_PRECISION:
  304. {
  305. rt_uint8_t temp;
  306. if (!(value == SHT20_RES_12_14BIT || value == SHT20_RES_8_12BIT || value == SHT20_RES_10_13BIT || value == SHT20_RES_11_11BIT))
  307. {
  308. LOG_E("Parameter value is invalid");
  309. return -RT_ERROR;
  310. }
  311. /* read user data */
  312. read_regs(dev->i2c, USER_REG_R, 1, &temp);
  313. if (temp != value)
  314. {
  315. value |= temp & (~SHT20_RES_MASK);
  316. write_reg(dev->i2c, USER_REG_W, value);
  317. }
  318. break;
  319. }
  320. case SHT20_PARAM_BATTERY_STATUS:
  321. {
  322. rt_uint8_t temp;
  323. if (!(value == SHT20_BATTERY_HIGH || value == SHT20_BATTERY_LOW))
  324. {
  325. LOG_E("Parameter value is invalid");
  326. return -RT_ERROR;
  327. }
  328. /* read user data */
  329. read_regs(dev->i2c, USER_REG_R, 1, &temp);
  330. if (temp != value)
  331. {
  332. value |= temp & (~SHT20_BATTERY_MASK);
  333. write_reg(dev->i2c, USER_REG_W, value);
  334. }
  335. break;
  336. }
  337. case SHT20_PARAM_HEATING:
  338. {
  339. rt_uint8_t temp;
  340. if (!(value == SHT20_HEATER_ON || value == SHT20_HEATER_OFF))
  341. {
  342. LOG_E("Parameter value is invalid");
  343. return -RT_ERROR;
  344. }
  345. /* read user data */
  346. read_regs(dev->i2c, USER_REG_R, 1, &temp);
  347. if (temp != value)
  348. {
  349. value |= temp & (~SHT20_HEATER_MASK);
  350. write_reg(dev->i2c, USER_REG_W, value);
  351. }
  352. break;
  353. }
  354. }
  355. return RT_EOK;
  356. }
  357. /**
  358. * This function gets parameter of sht20 sensor
  359. *
  360. * @param dev the pointer of device driver structure
  361. * @param type the parameter type of device
  362. * @param value the pointer value of type
  363. *
  364. * @return the getting parameter status,RT_EOK reprensents getting successfully.
  365. */
  366. rt_err_t sht20_get_param(sht20_device_t dev, sht20_param_type_t type, rt_uint8_t *value)
  367. {
  368. RT_ASSERT(dev);
  369. switch (type)
  370. {
  371. case SHT20_PARAM_PRECISION:
  372. {
  373. rt_uint8_t temp;
  374. /* read user data */
  375. read_regs(dev->i2c, USER_REG_R, 1, &temp);
  376. *value = temp & SHT20_RES_MASK;
  377. break;
  378. }
  379. case SHT20_PARAM_BATTERY_STATUS:
  380. {
  381. rt_uint8_t temp;
  382. /* read user data */
  383. read_regs(dev->i2c, USER_REG_R, 1, &temp);
  384. *value = temp & SHT20_BATTERY_MASK;
  385. break;
  386. }
  387. case SHT20_PARAM_HEATING:
  388. {
  389. rt_uint8_t temp;
  390. /* read user data */
  391. read_regs(dev->i2c, USER_REG_R, 1, &temp);
  392. *value = temp & SHT20_HEATER_MASK;
  393. break;
  394. }
  395. }
  396. return RT_EOK;
  397. }
  398. void sht20(int argc, char *argv[])
  399. {
  400. static sht20_device_t dev = RT_NULL;
  401. if (argc > 1)
  402. {
  403. if (!strcmp(argv[1], "probe"))
  404. {
  405. if (argc > 2)
  406. {
  407. /* initialize the sensor when first probe */
  408. if (!dev || strcmp(dev->i2c->parent.parent.name, argv[2]))
  409. {
  410. /* deinit the old device */
  411. if (dev)
  412. {
  413. sht20_deinit(dev);
  414. }
  415. dev = sht20_init(argv[2]);
  416. }
  417. }
  418. else
  419. {
  420. rt_kprintf("sht20 probe <dev_name> - probe sensor by given name\n");
  421. }
  422. }
  423. else if (!strcmp(argv[1], "read"))
  424. {
  425. if (dev)
  426. {
  427. float humidity;
  428. float temperature;
  429. /* read the sensor data */
  430. humidity = sht20_read_humidity(dev);
  431. temperature = sht20_read_temperature(dev);
  432. rt_kprintf("read sht20 sensor humidity : %d.%d %%\n", (int)humidity, (int)(humidity * 10) % 10);
  433. rt_kprintf("read sht20 sensor temperature: %d.%d \n", (int)temperature, (int)(temperature * 10) % 10);
  434. }
  435. else
  436. {
  437. rt_kprintf("Please using 'sht20 probe <dev_name>' first\n");
  438. }
  439. }
  440. else
  441. {
  442. rt_kprintf("Unknown command. Please enter 'sht20' for help\n");
  443. }
  444. }
  445. else
  446. {
  447. rt_kprintf("Usage:\n");
  448. rt_kprintf("sht20 probe <dev_name> - probe sensor by given name\n");
  449. rt_kprintf("sht20 read - read sensor sht20 data\n");
  450. }
  451. }
  452. MSH_CMD_EXPORT(sht20, sht20 sensor function);
  453. #endif /* PKG_USING_SHT2X */