OneWireSensor.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. #include "OneWireSensor.h"
  2. #include "../Sensors.h"
  3. //Интервал опроса датчиков (мс)
  4. #define POLLING_INTERVAL 2000
  5. //Максимальное количество попугаев ожидания датчика
  6. #define POLLING_TIMEOUT_TICKS 10000
  7. void unitemp_oneWire_sensorAlloc(Sensor* sensor, SensorType st) {
  8. OneWireSensor* instance = malloc(sizeof(OneWireSensor));
  9. instance->interface = ONE_WIRE;
  10. instance->lastPollingTime = 0xFFFFFFFF;
  11. sensor->initializer = unitemp_oneWire_sensorInit;
  12. sensor->deinitializer = unitemp_oneWire_sensorDeInit;
  13. sensor->updater = unitemp_oneWire_updateData;
  14. sensor->instance = instance;
  15. sensor->type = st;
  16. }
  17. bool unitemp_oneWire_sensorInit(void* sensor) {
  18. OneWireSensor* instance = ((Sensor*)sensor)->instance;
  19. if(instance == NULL || instance->gpio == NULL) {
  20. FURI_LOG_E(APP_NAME, "Sensor pointer is null!");
  21. return false;
  22. }
  23. //Высокий уровень по умолчанию
  24. furi_hal_gpio_write(instance->gpio->pin, true);
  25. //Режим работы - OpenDrain, подтяжка включается на всякий случай
  26. furi_hal_gpio_init(
  27. instance->gpio->pin, //Порт FZ
  28. GpioModeOutputOpenDrain, //Режим работы - открытый сток
  29. GpioPullUp, //Принудительная подтяжка линии данных к питанию
  30. GpioSpeedVeryHigh); //Скорость работы - максимальная
  31. return true;
  32. }
  33. bool unitemp_oneWire_sensorDeInit(void* sensor) {
  34. OneWireSensor* instance = ((Sensor*)sensor)->instance;
  35. if(instance == NULL || instance->gpio == NULL) return false;
  36. //Низкий уровень по умолчанию
  37. furi_hal_gpio_write(instance->gpio->pin, false);
  38. //Режим работы - аналог, подтяжка выключена
  39. furi_hal_gpio_init(
  40. instance->gpio->pin, //Порт FZ
  41. GpioModeAnalog, //Режим работы - аналог
  42. GpioPullNo, //Подтяжка выключена
  43. GpioSpeedLow); //Скорость работы - минимальная
  44. return true;
  45. }
  46. bool unitemp_oneWire_sensorSetGPIO(Sensor* sensor, const GPIO* gpio) {
  47. if(sensor == NULL || gpio == NULL) return false;
  48. OneWireSensor* instance = sensor->instance;
  49. instance->gpio = gpio;
  50. return true;
  51. }
  52. const GPIO* unitemp_oneWire_sensorGetGPIO(Sensor* sensor) {
  53. if(sensor == NULL) return NULL;
  54. OneWireSensor* instance = sensor->instance;
  55. return instance->gpio;
  56. }
  57. UnitempStatus unitemp_oneWire_updateData(void* sensor) {
  58. OneWireSensor* instance = ((Sensor*)sensor)->instance;
  59. //Проверка на допустимость опроса датчика
  60. if(furi_get_tick() - instance->lastPollingTime < POLLING_INTERVAL) {
  61. //Возврат ошибки если последний опрос датчика был неудачным
  62. if(instance->lastHum == -128.0f && instance->lastTemp == -128.0f) {
  63. ((Sensor*)sensor)->hum = instance->lastHum;
  64. ((Sensor*)sensor)->temp = instance->lastTemp;
  65. return UT_TIMEOUT;
  66. }
  67. //Выход в случае раннего опроса
  68. ((Sensor*)sensor)->hum = instance->lastHum;
  69. ((Sensor*)sensor)->temp = instance->lastTemp;
  70. return UT_EARLYPOOL;
  71. }
  72. //Массив для приёма данных
  73. uint8_t data[5] = {0};
  74. //Сохранение времени последнего опроса
  75. instance->lastPollingTime = furi_get_tick();
  76. /* Запрос */
  77. //Опускание линии
  78. furi_hal_gpio_write(instance->gpio->pin, false);
  79. //Ожидание более 18 мс
  80. furi_delay_ms(19);
  81. //Выключение прерываний, чтобы ничто не мешало обработке данных
  82. __disable_irq();
  83. //Подъём линии
  84. furi_hal_gpio_write(instance->gpio->pin, true);
  85. /* Ответ датчика */
  86. //Переменная-счётчик
  87. uint16_t timeout = 0;
  88. //Ожидание подъёма линии
  89. while(!furi_hal_gpio_read(instance->gpio->pin)) {
  90. timeout++;
  91. if(timeout > POLLING_TIMEOUT_TICKS) {
  92. //Включение прерываний
  93. __enable_irq();
  94. //Запись неправильных значений
  95. instance->lastHum = -128.0f;
  96. instance->lastTemp = -128.0f;
  97. //Возврат признака отсутствующего датчика
  98. return UT_TIMEOUT;
  99. }
  100. }
  101. timeout = 0;
  102. //Ожидание спада линии
  103. while(furi_hal_gpio_read(instance->gpio->pin)) {
  104. timeout++;
  105. if(timeout > POLLING_TIMEOUT_TICKS) {
  106. //Включение прерываний
  107. __enable_irq();
  108. //Запись неправильных значений
  109. instance->lastHum = -128.0f;
  110. instance->lastTemp = -128.0f;
  111. //Возврат признака отсутствующего датчика
  112. return UT_TIMEOUT;
  113. }
  114. }
  115. //Ожидание подъёма линии
  116. while(!furi_hal_gpio_read(instance->gpio->pin)) {
  117. timeout++;
  118. if(timeout > POLLING_TIMEOUT_TICKS) {
  119. //Включение прерываний
  120. __enable_irq();
  121. //Запись неправильных значений
  122. instance->lastHum = -128.0f;
  123. instance->lastTemp = -128.0f;
  124. //Возврат признака отсутствующего датчика
  125. return UT_TIMEOUT;
  126. }
  127. }
  128. timeout = 0;
  129. //Ожидание спада линии
  130. while(furi_hal_gpio_read(instance->gpio->pin)) {
  131. timeout++;
  132. if(timeout > POLLING_TIMEOUT_TICKS) {
  133. //Включение прерываний
  134. __enable_irq();
  135. //Запись неправильных значений
  136. instance->lastHum = -128.0f;
  137. instance->lastTemp = -128.0f;
  138. //Возврат признака отсутствующего датчика
  139. return UT_TIMEOUT;
  140. }
  141. }
  142. /* Чтение данных с датчика*/
  143. //Приём 5 байт
  144. for(uint8_t a = 0; a < 5; a++) {
  145. for(uint8_t b = 7; b != 255; b--) {
  146. uint16_t hT = 0, lT = 0;
  147. //Пока линия в низком уровне, инкремент переменной lT
  148. while(!furi_hal_gpio_read(instance->gpio->pin) && lT != 65535) lT++;
  149. //Пока линия в высоком уровне, инкремент переменной hT
  150. while(furi_hal_gpio_read(instance->gpio->pin) && hT != 65535) hT++;
  151. //Если hT больше lT, то пришла единица
  152. if(hT > lT) data[a] |= (1 << b);
  153. }
  154. }
  155. //Включение прерываний
  156. __enable_irq();
  157. //Проверка контрольной суммы
  158. if((uint8_t)(data[0] + data[1] + data[2] + data[3]) != data[4]) {
  159. //Запись неправильных значений
  160. instance->lastHum = -128.0f;
  161. instance->lastTemp = -128.0f;
  162. //Если контрольная сумма не совпала, возврат ошибки
  163. return UT_BADCRC;
  164. }
  165. /* Преобразование данных в явный вид */
  166. //DHT11 и DHT12
  167. if(((Sensor*)sensor)->type == DHT11 || ((Sensor*)sensor)->type == DHT12_1W) {
  168. instance->lastHum = (float)data[0];
  169. instance->lastTemp = (float)data[2];
  170. //Проверка на отрицательность температуры
  171. if(data[3] != 0) {
  172. //Проверка знака
  173. if(!(data[3] & (1 << 7))) {
  174. //Добавление положительной дробной части
  175. instance->lastTemp += data[3] * 0.1f;
  176. } else {
  177. //А тут делаем отрицательное значение
  178. data[3] &= ~(1 << 7);
  179. instance->lastTemp += data[3] * 0.1f;
  180. instance->lastTemp *= -1;
  181. }
  182. }
  183. }
  184. //DHT21, DHT22, AM2320
  185. if(((Sensor*)sensor)->type == DHT21 || ((Sensor*)sensor)->type == DHT22 ||
  186. ((Sensor*)sensor)->type == AM2320_1W) {
  187. instance->lastHum = (float)(((uint16_t)data[0] << 8) | data[1]) / 10;
  188. //Проверка на отрицательность температуры
  189. if(!(data[2] & (1 << 7))) {
  190. instance->lastTemp = (float)(((uint16_t)data[2] << 8) | data[3]) / 10;
  191. } else {
  192. data[2] &= ~(1 << 7);
  193. instance->lastTemp = (float)(((uint16_t)data[2] << 8) | data[3]) / 10 * -1;
  194. }
  195. }
  196. ((Sensor*)sensor)->hum = instance->lastHum;
  197. ((Sensor*)sensor)->temp = instance->lastTemp;
  198. //Возврат признака успешного опроса
  199. return UT_OK;
  200. }