| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- /*
- Unitemp - Universal temperature reader
- Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n)
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
- #include "SingleWireSensor.h"
- //Максимальное количество попугаев ожидания датчика
- #define POLLING_TIMEOUT_TICKS 500
- /* Типы датчиков и их параметры */
- const SensorType DHT11 = {
- .typename = "DHT11",
- .interface = &SINGLE_WIRE,
- .datatype = UT_DATA_TYPE_TEMP_HUM,
- .pollingInterval = 2000,
- .allocator = unitemp_singlewire_alloc,
- .mem_releaser = unitemp_singlewire_free,
- .initializer = unitemp_singlewire_init,
- .deinitializer = unitemp_singlewire_deinit,
- .updater = unitemp_singlewire_update};
- const SensorType DHT12_SW = {
- .typename = "DHT12",
- .interface = &SINGLE_WIRE,
- .datatype = UT_DATA_TYPE_TEMP_HUM,
- .pollingInterval = 2000,
- .allocator = unitemp_singlewire_alloc,
- .mem_releaser = unitemp_singlewire_free,
- .initializer = unitemp_singlewire_init,
- .deinitializer = unitemp_singlewire_deinit,
- .updater = unitemp_singlewire_update};
- const SensorType DHT21 = {
- .typename = "DHT21",
- .altname = "DHT21/AM2301",
- .interface = &SINGLE_WIRE,
- .datatype = UT_DATA_TYPE_TEMP_HUM,
- .pollingInterval = 1000,
- .allocator = unitemp_singlewire_alloc,
- .mem_releaser = unitemp_singlewire_free,
- .initializer = unitemp_singlewire_init,
- .deinitializer = unitemp_singlewire_deinit,
- .updater = unitemp_singlewire_update};
- const SensorType DHT22 = {
- .typename = "DHT22",
- .altname = "DHT22/AM2302",
- .interface = &SINGLE_WIRE,
- .datatype = UT_DATA_TYPE_TEMP_HUM,
- .pollingInterval = 2000,
- .allocator = unitemp_singlewire_alloc,
- .mem_releaser = unitemp_singlewire_free,
- .initializer = unitemp_singlewire_init,
- .deinitializer = unitemp_singlewire_deinit,
- .updater = unitemp_singlewire_update};
- const SensorType AM2320_SW = {
- .typename = "AM2320",
- .altname = "AM2320 (single wire)",
- .interface = &SINGLE_WIRE,
- .datatype = UT_DATA_TYPE_TEMP_HUM,
- .pollingInterval = 2000,
- .allocator = unitemp_singlewire_alloc,
- .mem_releaser = unitemp_singlewire_free,
- .initializer = unitemp_singlewire_init,
- .deinitializer = unitemp_singlewire_deinit,
- .updater = unitemp_singlewire_update};
- bool unitemp_singlewire_alloc(Sensor* sensor, char* args) {
- if(args == NULL) return false;
- SingleWireSensor* instance = malloc(sizeof(SingleWireSensor));
- if(instance == NULL) {
- FURI_LOG_E(APP_NAME, "Sensor %s instance allocation error", sensor->name);
- return false;
- }
- sensor->instance = instance;
- int gpio = 255;
- sscanf(args, "%d", &gpio);
- if(unitemp_singlewire_sensorSetGPIO(sensor, unitemp_gpio_getFromInt(gpio))) {
- return true;
- }
- FURI_LOG_E(APP_NAME, "Sensor %s GPIO setting error", sensor->name);
- free(instance);
- return false;
- }
- bool unitemp_singlewire_free(Sensor* sensor) {
- free(sensor->instance);
- return true;
- }
- bool unitemp_singlewire_init(Sensor* sensor) {
- SingleWireSensor* instance = ((Sensor*)sensor)->instance;
- if(instance == NULL || instance->gpio == NULL) {
- FURI_LOG_E(APP_NAME, "Sensor pointer is null!");
- return false;
- }
- unitemp_gpio_lock(instance->gpio, &SINGLE_WIRE);
- //Высокий уровень по умолчанию
- furi_hal_gpio_write(instance->gpio->pin, true);
- //Режим работы - OpenDrain, подтяжка включается на всякий случай
- furi_hal_gpio_init(
- instance->gpio->pin, //Порт FZ
- GpioModeOutputOpenDrain, //Режим работы - открытый сток
- GpioPullUp, //Принудительная подтяжка линии данных к питанию
- GpioSpeedVeryHigh); //Скорость работы - максимальная
- return true;
- }
- bool unitemp_singlewire_deinit(Sensor* sensor) {
- SingleWireSensor* instance = ((Sensor*)sensor)->instance;
- if(instance == NULL || instance->gpio == NULL) return false;
- unitemp_gpio_unlock(instance->gpio);
- //Низкий уровень по умолчанию
- furi_hal_gpio_write(instance->gpio->pin, false);
- //Режим работы - аналог, подтяжка выключена
- furi_hal_gpio_init(
- instance->gpio->pin, //Порт FZ
- GpioModeAnalog, //Режим работы - аналог
- GpioPullNo, //Подтяжка выключена
- GpioSpeedLow); //Скорость работы - минимальная
- return true;
- }
- bool unitemp_singlewire_sensorSetGPIO(Sensor* sensor, const GPIO* gpio) {
- if(sensor == NULL || gpio == NULL) return false;
- SingleWireSensor* instance = sensor->instance;
- instance->gpio = gpio;
- return true;
- }
- const GPIO* unitemp_singlewire_sensorGetGPIO(Sensor* sensor) {
- if(sensor == NULL) return NULL;
- SingleWireSensor* instance = sensor->instance;
- return instance->gpio;
- }
- UnitempStatus unitemp_singlewire_update(Sensor* sensor) {
- SingleWireSensor* instance = sensor->instance;
- //Массив для приёма данных
- uint8_t data[5] = {0};
- /* Запрос */
- //Опускание линии
- furi_hal_gpio_write(instance->gpio->pin, false);
- //Ожидание более 18 мс
- furi_delay_ms(19);
- //Выключение прерываний, чтобы ничто не мешало обработке данных
- __disable_irq();
- //Подъём линии
- furi_hal_gpio_write(instance->gpio->pin, true);
- /* Ответ датчика */
- //Переменная-счётчик
- uint16_t timeout = 0;
- //Ожидание подъёма линии
- while(!furi_hal_gpio_read(instance->gpio->pin)) {
- timeout++;
- if(timeout > POLLING_TIMEOUT_TICKS) {
- //Включение прерываний
- __enable_irq();
- //Возврат признака отсутствующего датчика
- return UT_SENSORSTATUS_TIMEOUT;
- }
- }
- timeout = 0;
- //Ожидание спада линии
- while(furi_hal_gpio_read(instance->gpio->pin)) {
- timeout++;
- if(timeout > POLLING_TIMEOUT_TICKS) {
- //Включение прерываний
- __enable_irq();
- //Возврат признака отсутствующего датчика
- return UT_SENSORSTATUS_TIMEOUT;
- }
- }
- //Ожидание подъёма линии
- while(!furi_hal_gpio_read(instance->gpio->pin)) {
- timeout++;
- if(timeout > POLLING_TIMEOUT_TICKS) {
- //Включение прерываний
- __enable_irq();
- //Возврат признака отсутствующего датчика
- return UT_SENSORSTATUS_TIMEOUT;
- }
- }
- timeout = 0;
- //Ожидание спада линии
- while(furi_hal_gpio_read(instance->gpio->pin)) {
- timeout++;
- if(timeout > POLLING_TIMEOUT_TICKS) {
- //Включение прерываний
- __enable_irq();
- //Возврат признака отсутствующего датчика
- return UT_SENSORSTATUS_TIMEOUT;
- }
- }
- /* Чтение данных с датчика*/
- //Приём 5 байт
- for(uint8_t a = 0; a < 5; a++) {
- for(uint8_t b = 7; b != 255; b--) {
- uint16_t hT = 0, lT = 0;
- //Пока линия в низком уровне, инкремент переменной lT
- while(!furi_hal_gpio_read(instance->gpio->pin) && lT != 65535) lT++;
- //Пока линия в высоком уровне, инкремент переменной hT
- while(furi_hal_gpio_read(instance->gpio->pin) && hT != 65535) hT++;
- //Если hT больше lT, то пришла единица
- if(hT > lT) data[a] |= (1 << b);
- }
- }
- //Включение прерываний
- __enable_irq();
- //Проверка контрольной суммы
- if((uint8_t)(data[0] + data[1] + data[2] + data[3]) != data[4]) {
- //Если контрольная сумма не совпала, возврат ошибки
- return UT_SENSORSTATUS_BADCRC;
- }
- /* Преобразование данных в явный вид */
- //DHT11 и DHT12
- if(sensor->type == &DHT11 || sensor->type == &DHT12_SW) {
- sensor->hum = (float)data[0];
- sensor->temp = (float)data[2];
- //Проверка на отрицательность температуры
- if(data[3] != 0) {
- //Проверка знака
- if(!(data[3] & (1 << 7))) {
- //Добавление положительной дробной части
- sensor->temp += data[3] * 0.1f;
- } else {
- //А тут делаем отрицательное значение
- data[3] &= ~(1 << 7);
- sensor->temp += data[3] * 0.1f;
- sensor->temp *= -1;
- }
- }
- }
- //DHT21, DHT22, AM2320
- if(sensor->type == &DHT21 || sensor->type == &DHT22 || sensor->type == &AM2320_SW) {
- sensor->hum = (float)(((uint16_t)data[0] << 8) | data[1]) / 10;
- uint16_t raw = (((uint16_t)data[2] << 8) | data[3]);
- //Проверка на отрицательность температуры
- if(READ_BIT(raw, 1 << 15)) {
- //Проверка на способ кодирования данных
- if(READ_BIT(raw, 0x6000)) {
- //Не оригинал
- sensor->temp = (float)((int16_t)raw) / 10;
- } else {
- //Оригинальный датчик
- CLEAR_BIT(raw, 1 << 15);
- sensor->temp = (float)(raw) / -10;
- }
- } else {
- sensor->temp = (float)(raw) / 10;
- }
- }
- //Возврат признака успешного опроса
- return UT_SENSORSTATUS_OK;
- }
|