OneWireSensor.c 9.2 KB

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