SingleWireSensor.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. /*
  2. Unitemp - Universal temperature reader
  3. Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n)
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. */
  15. #include "SingleWireSensor.h"
  16. //Максимальное количество попугаев ожидания датчика
  17. #define POLLING_TIMEOUT_TICKS 500
  18. /* Типы датчиков и их параметры */
  19. const SensorType DHT11 = {
  20. .typename = "DHT11",
  21. .interface = &SINGLE_WIRE,
  22. .datatype = UT_DATA_TYPE_TEMP_HUM,
  23. .pollingInterval = 2000,
  24. .allocator = unitemp_singlewire_alloc,
  25. .mem_releaser = unitemp_singlewire_free,
  26. .initializer = unitemp_singlewire_init,
  27. .deinitializer = unitemp_singlewire_deinit,
  28. .updater = unitemp_singlewire_update};
  29. const SensorType DHT12_SW = {
  30. .typename = "DHT12",
  31. .interface = &SINGLE_WIRE,
  32. .datatype = UT_DATA_TYPE_TEMP_HUM,
  33. .pollingInterval = 2000,
  34. .allocator = unitemp_singlewire_alloc,
  35. .mem_releaser = unitemp_singlewire_free,
  36. .initializer = unitemp_singlewire_init,
  37. .deinitializer = unitemp_singlewire_deinit,
  38. .updater = unitemp_singlewire_update};
  39. const SensorType DHT21 = {
  40. .typename = "DHT21",
  41. .altname = "DHT21/AM2301",
  42. .interface = &SINGLE_WIRE,
  43. .datatype = UT_DATA_TYPE_TEMP_HUM,
  44. .pollingInterval = 1000,
  45. .allocator = unitemp_singlewire_alloc,
  46. .mem_releaser = unitemp_singlewire_free,
  47. .initializer = unitemp_singlewire_init,
  48. .deinitializer = unitemp_singlewire_deinit,
  49. .updater = unitemp_singlewire_update};
  50. const SensorType DHT22 = {
  51. .typename = "DHT22",
  52. .altname = "DHT22/AM2302",
  53. .interface = &SINGLE_WIRE,
  54. .datatype = UT_DATA_TYPE_TEMP_HUM,
  55. .pollingInterval = 2000,
  56. .allocator = unitemp_singlewire_alloc,
  57. .mem_releaser = unitemp_singlewire_free,
  58. .initializer = unitemp_singlewire_init,
  59. .deinitializer = unitemp_singlewire_deinit,
  60. .updater = unitemp_singlewire_update};
  61. const SensorType AM2320_SW = {
  62. .typename = "AM2320",
  63. .altname = "AM2320 (single wire)",
  64. .interface = &SINGLE_WIRE,
  65. .datatype = UT_DATA_TYPE_TEMP_HUM,
  66. .pollingInterval = 2000,
  67. .allocator = unitemp_singlewire_alloc,
  68. .mem_releaser = unitemp_singlewire_free,
  69. .initializer = unitemp_singlewire_init,
  70. .deinitializer = unitemp_singlewire_deinit,
  71. .updater = unitemp_singlewire_update};
  72. bool unitemp_singlewire_alloc(Sensor* sensor, char* args) {
  73. if(args == NULL) return false;
  74. SingleWireSensor* instance = malloc(sizeof(SingleWireSensor));
  75. if(instance == NULL) {
  76. FURI_LOG_E(APP_NAME, "Sensor %s instance allocation error", sensor->name);
  77. return false;
  78. }
  79. sensor->instance = instance;
  80. int gpio = 255;
  81. sscanf(args, "%d", &gpio);
  82. if(unitemp_singlewire_sensorSetGPIO(sensor, unitemp_gpio_getFromInt(gpio))) {
  83. return true;
  84. }
  85. FURI_LOG_E(APP_NAME, "Sensor %s GPIO setting error", sensor->name);
  86. free(instance);
  87. return false;
  88. }
  89. bool unitemp_singlewire_free(Sensor* sensor) {
  90. free(sensor->instance);
  91. return true;
  92. }
  93. bool unitemp_singlewire_init(Sensor* sensor) {
  94. SingleWireSensor* instance = ((Sensor*)sensor)->instance;
  95. if(instance == NULL || instance->gpio == NULL) {
  96. FURI_LOG_E(APP_NAME, "Sensor pointer is null!");
  97. return false;
  98. }
  99. unitemp_gpio_lock(instance->gpio, &SINGLE_WIRE);
  100. //Высокий уровень по умолчанию
  101. furi_hal_gpio_write(instance->gpio->pin, true);
  102. //Режим работы - OpenDrain, подтяжка включается на всякий случай
  103. furi_hal_gpio_init(
  104. instance->gpio->pin, //Порт FZ
  105. GpioModeOutputOpenDrain, //Режим работы - открытый сток
  106. GpioPullUp, //Принудительная подтяжка линии данных к питанию
  107. GpioSpeedVeryHigh); //Скорость работы - максимальная
  108. return true;
  109. }
  110. bool unitemp_singlewire_deinit(Sensor* sensor) {
  111. SingleWireSensor* instance = ((Sensor*)sensor)->instance;
  112. if(instance == NULL || instance->gpio == NULL) return false;
  113. unitemp_gpio_unlock(instance->gpio);
  114. //Низкий уровень по умолчанию
  115. furi_hal_gpio_write(instance->gpio->pin, false);
  116. //Режим работы - аналог, подтяжка выключена
  117. furi_hal_gpio_init(
  118. instance->gpio->pin, //Порт FZ
  119. GpioModeAnalog, //Режим работы - аналог
  120. GpioPullNo, //Подтяжка выключена
  121. GpioSpeedLow); //Скорость работы - минимальная
  122. return true;
  123. }
  124. bool unitemp_singlewire_sensorSetGPIO(Sensor* sensor, const GPIO* gpio) {
  125. if(sensor == NULL || gpio == NULL) return false;
  126. SingleWireSensor* instance = sensor->instance;
  127. instance->gpio = gpio;
  128. return true;
  129. }
  130. const GPIO* unitemp_singlewire_sensorGetGPIO(Sensor* sensor) {
  131. if(sensor == NULL) return NULL;
  132. SingleWireSensor* instance = sensor->instance;
  133. return instance->gpio;
  134. }
  135. UnitempStatus unitemp_singlewire_update(Sensor* sensor) {
  136. SingleWireSensor* instance = sensor->instance;
  137. //Массив для приёма данных
  138. uint8_t data[5] = {0};
  139. /* Запрос */
  140. //Опускание линии
  141. furi_hal_gpio_write(instance->gpio->pin, false);
  142. //Ожидание более 18 мс
  143. furi_delay_ms(19);
  144. //Выключение прерываний, чтобы ничто не мешало обработке данных
  145. __disable_irq();
  146. //Подъём линии
  147. furi_hal_gpio_write(instance->gpio->pin, true);
  148. /* Ответ датчика */
  149. //Переменная-счётчик
  150. uint16_t timeout = 0;
  151. //Ожидание подъёма линии
  152. while(!furi_hal_gpio_read(instance->gpio->pin)) {
  153. timeout++;
  154. if(timeout > POLLING_TIMEOUT_TICKS) {
  155. //Включение прерываний
  156. __enable_irq();
  157. //Возврат признака отсутствующего датчика
  158. return UT_SENSORSTATUS_TIMEOUT;
  159. }
  160. }
  161. timeout = 0;
  162. //Ожидание спада линии
  163. while(furi_hal_gpio_read(instance->gpio->pin)) {
  164. timeout++;
  165. if(timeout > POLLING_TIMEOUT_TICKS) {
  166. //Включение прерываний
  167. __enable_irq();
  168. //Возврат признака отсутствующего датчика
  169. return UT_SENSORSTATUS_TIMEOUT;
  170. }
  171. }
  172. //Ожидание подъёма линии
  173. while(!furi_hal_gpio_read(instance->gpio->pin)) {
  174. timeout++;
  175. if(timeout > POLLING_TIMEOUT_TICKS) {
  176. //Включение прерываний
  177. __enable_irq();
  178. //Возврат признака отсутствующего датчика
  179. return UT_SENSORSTATUS_TIMEOUT;
  180. }
  181. }
  182. timeout = 0;
  183. //Ожидание спада линии
  184. while(furi_hal_gpio_read(instance->gpio->pin)) {
  185. timeout++;
  186. if(timeout > POLLING_TIMEOUT_TICKS) {
  187. //Включение прерываний
  188. __enable_irq();
  189. //Возврат признака отсутствующего датчика
  190. return UT_SENSORSTATUS_TIMEOUT;
  191. }
  192. }
  193. /* Чтение данных с датчика*/
  194. //Приём 5 байт
  195. for(uint8_t a = 0; a < 5; a++) {
  196. for(uint8_t b = 7; b != 255; b--) {
  197. uint16_t hT = 0, lT = 0;
  198. //Пока линия в низком уровне, инкремент переменной lT
  199. while(!furi_hal_gpio_read(instance->gpio->pin) && lT != 65535) lT++;
  200. //Пока линия в высоком уровне, инкремент переменной hT
  201. while(furi_hal_gpio_read(instance->gpio->pin) && hT != 65535) hT++;
  202. //Если hT больше lT, то пришла единица
  203. if(hT > lT) data[a] |= (1 << b);
  204. }
  205. }
  206. //Включение прерываний
  207. __enable_irq();
  208. //Проверка контрольной суммы
  209. if((uint8_t)(data[0] + data[1] + data[2] + data[3]) != data[4]) {
  210. //Если контрольная сумма не совпала, возврат ошибки
  211. return UT_SENSORSTATUS_BADCRC;
  212. }
  213. /* Преобразование данных в явный вид */
  214. //DHT11 и DHT12
  215. if(sensor->type == &DHT11 || sensor->type == &DHT12_SW) {
  216. sensor->hum = (float)data[0];
  217. sensor->temp = (float)data[2];
  218. //Проверка на отрицательность температуры
  219. if(data[3] != 0) {
  220. //Проверка знака
  221. if(!(data[3] & (1 << 7))) {
  222. //Добавление положительной дробной части
  223. sensor->temp += data[3] * 0.1f;
  224. } else {
  225. //А тут делаем отрицательное значение
  226. data[3] &= ~(1 << 7);
  227. sensor->temp += data[3] * 0.1f;
  228. sensor->temp *= -1;
  229. }
  230. }
  231. }
  232. //DHT21, DHT22, AM2320
  233. if(sensor->type == &DHT21 || sensor->type == &DHT22 || sensor->type == &AM2320_SW) {
  234. sensor->hum = (float)(((uint16_t)data[0] << 8) | data[1]) / 10;
  235. uint16_t raw = (((uint16_t)data[2] << 8) | data[3]);
  236. //Проверка на отрицательность температуры
  237. if(READ_BIT(raw, 1 << 15)) {
  238. //Проверка на способ кодирования данных
  239. if(READ_BIT(raw, 0x6000)) {
  240. //Не оригинал
  241. sensor->temp = (float)((int16_t)raw) / 10;
  242. } else {
  243. //Оригинальный датчик
  244. CLEAR_BIT(raw, 1 << 15);
  245. sensor->temp = (float)(raw) / -10;
  246. }
  247. } else {
  248. sensor->temp = (float)(raw) / 10;
  249. }
  250. }
  251. //Возврат признака успешного опроса
  252. return UT_SENSORSTATUS_OK;
  253. }