Просмотр исходного кода

Implemented many onewire and sensor functions

Victor 3 лет назад
Родитель
Сommit
f23fc262c6
6 измененных файлов с 313 добавлено и 16 удалено
  1. 165 1
      interfaces/OneWire.c
  2. 24 0
      interfaces/OneWire.h
  3. 65 0
      interfaces/Sensors.c
  4. 35 1
      interfaces/Sensors.h
  5. 19 12
      unitemp.c
  6. 5 2
      unitemp.h

+ 165 - 1
interfaces/OneWire.c

@@ -1,2 +1,166 @@
 #include "OneWire.h"
-#include "Sensors.h"
+#include "Sensors.h"
+
+//Интервал опроса датчиков (мс)
+#define POLLING_INTERVAL 2000
+//Максимальное количество попугаев ожидания датчика
+#define POLLING_TIMEOUT_TICKS 10000
+
+bool unitemp_oneWire_sensorInit(OneWireSensor* sensor) {
+    if(sensor == NULL || sensor->gpio == NULL) return false;
+    //Высокий уровень по умолчанию
+    furi_hal_gpio_write(sensor->gpio->pin, true);
+    //Режим работы - OpenDrain, подтяжка включается на всякий случай
+    furi_hal_gpio_init(
+        sensor->gpio->pin, //Порт FZ
+        GpioModeOutputOpenDrain, //Режим работы - открытый сток
+        GpioPullUp, //Принудительная подтяжка линии данных к питанию
+        GpioSpeedVeryHigh); //Скорость работы - максимальная
+    return true;
+}
+
+bool unitemp_oneWire_sensorDeInit(OneWireSensor* sensor) {
+    if(sensor == NULL || sensor->gpio == NULL) return false;
+    //Низкий уровень по умолчанию
+    furi_hal_gpio_write(sensor->gpio->pin, false);
+    //Режим работы - аналог, подтяжка выключена
+    furi_hal_gpio_init(
+        sensor->gpio->pin, //Порт FZ
+        GpioModeAnalog, //Режим работы - аналог
+        GpioPullNo, //Подтяжка выключена
+        GpioSpeedLow); //Скорость работы - минимальная
+    return true;
+}
+
+UnitempStatus unitemp_oneWire_getData(Sensor* sensor) {
+    OneWireSensor* instance = sensor->instance;
+    //Проверка на допустимость опроса датчика
+    if(furi_get_tick() - instance->lastPollingTime < POLLING_INTERVAL) {
+        //Выход в случае раннего опроса
+        return UT_EARLYPOOL;
+    }
+
+    //Массив для приёма данных
+    uint8_t data[5] = {0};
+
+    //Сохранение времени последнего опроса
+    instance->lastPollingTime = furi_get_tick();
+
+    /* Запрос */
+    //Опускание линии
+    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_TIMEOUT;
+        }
+    }
+    timeout = 0;
+
+    //Ожидание спада линии
+    while(furi_hal_gpio_read(instance->gpio->pin)) {
+        timeout++;
+        if(timeout > POLLING_TIMEOUT_TICKS) {
+            //Включение прерываний
+            __enable_irq();
+            //Возврат признака отсутствующего датчика
+            return UT_TIMEOUT;
+        }
+    }
+
+    //Ожидание подъёма линии
+    while(!furi_hal_gpio_read(instance->gpio->pin)) {
+        timeout++;
+        if(timeout > POLLING_TIMEOUT_TICKS) {
+            //Включение прерываний
+            __enable_irq();
+            //Возврат признака отсутствующего датчика
+            return UT_TIMEOUT;
+        }
+    }
+    timeout = 0;
+
+    //Ожидание спада линии
+    while(furi_hal_gpio_read(instance->gpio->pin)) {
+        timeout++;
+        if(timeout > POLLING_TIMEOUT_TICKS) {
+            //Включение прерываний
+            __enable_irq();
+            //Возврат признака отсутствующего датчика
+            return UT_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_BADCRC;
+    }
+
+    /* Преобразование данных в явный вид */
+    //DHT11 и DHT12
+    if(sensor->type == DHT11 || sensor->type == DHT12_1W) {
+        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_1W) {
+        sensor->hum = (float)(((uint16_t)data[0] << 8) | data[1]) * 0.1f;
+        //Проверка на отрицательность температуры
+        if(!(data[2] & (1 << 7))) {
+            sensor->temp = (float)(((uint16_t)data[2] << 8) | data[3]) * 0.1f;
+        } else {
+            data[2] &= ~(1 << 7);
+            sensor->temp = (float)(((uint16_t)data[2] << 8) | data[3]) * -0.1f;
+        }
+    }
+
+    //Возврат признака успешного опроса
+    return UT_OK;
+}

+ 24 - 0
interfaces/OneWire.h

@@ -13,4 +13,28 @@ typedef struct {
     uint32_t lastPollingTime;
 } OneWireSensor;
 
+/**
+ * @brief Инициализация датчика
+ * 
+ * @param sensor Указатель на инициализируемый датчик
+ * @return Истина если всё прошло успешно
+ */
+bool unitemp_oneWire_sensorInit(OneWireSensor* sensor);
+
+/**
+ * @brief Деинициализация датчика
+ * 
+ * @param sensor Указатель на инициализируемый датчик
+ * @return Истина если всё прошло успешно
+ */
+bool unitemp_oneWire_sensorDeInit(OneWireSensor* sensor);
+
+/**
+ * @brief Получение данных с датчика по однопроводному интерфейсу DHTxx и AM2xxx
+ * 
+ * @param sensor Указатель на датчик
+ * @return Статус опроса
+ */
+UnitempStatus unitemp_oneWire_getData(Sensor* sensor);
+
 #endif

+ 65 - 0
interfaces/Sensors.c

@@ -1,4 +1,7 @@
 #include "Sensors.h"
+#include "OneWire.h"
+
+#include <furi_hal_power.h>
 
 //Порты ввода/вывода, которые не были обозначены в общем списке
 const GpioPin SWC_10 = {.pin = LL_GPIO_PIN_14, .port = GPIOA};
@@ -55,4 +58,66 @@ const GPIO* unitemp_getGPIOFormInt(uint8_t name) {
         }
     }
     return NULL;
+}
+
+Sensor* unitemp_sensor_alloc(char* name, SensorType st) {
+    //Выделение памяти под датчик
+    Sensor* sensor = malloc(sizeof(Sensor));
+    sensor->name = name;
+    //Выделение памяти под инстанс DHT11, DHT12 (1W), DHT21, DHT22, AM2320 (1W)
+    if(st == DHT11 || st == DHT12_1W || st == DHT21 || st == DHT22 || st == AM2320_1W) {
+        if(sensor == NULL) return false;
+        OneWireSensor* instance = malloc(sizeof(OneWireSensor));
+        instance->interface = ONE_WIRE;
+        instance->lastPollingTime = 0;
+        sensor->instance = instance;
+        sensor->interface = ONE_WIRE;
+    }
+    return sensor;
+}
+
+bool unitemp_sensors_init(void) {
+    bool result = true;
+    //Включение 5V если на порту 1 FZ его нет
+    if(furi_hal_power_is_otg_enabled() != true) {
+        furi_hal_power_enable_otg();
+        FURI_LOG_D(APP_NAME, "OTG enabled");
+    }
+
+    //Перебор датчиков из списка
+    for(size_t i = 0; i < app->sensors_count; i++) {
+        if(app->sensors[i]->interface == ONE_WIRE) {
+            if(!unitemp_oneWire_sensorInit(app->sensors[i]->instance)) {
+                FURI_LOG_W(
+                    APP_NAME,
+                    "An error occurred during sensor initialization %s",
+                    app->sensors[i]->name);
+                result = false;
+            }
+        }
+    }
+    return result;
+}
+
+bool unitemp_sensors_deInit(void) {
+    bool result = true;
+    //Выключение 5 В если до этого оно не было включено
+    if(app->settings.lastOTGState != true) {
+        furi_hal_power_disable_otg();
+        FURI_LOG_D(APP_NAME, "OTG disabled");
+    }
+
+    //Перебор датчиков из списка
+    for(size_t i = 0; i < app->sensors_count; i++) {
+        if(app->sensors[i]->interface == ONE_WIRE) {
+            if(!unitemp_oneWire_sensorDeInit(app->sensors[i]->instance)) {
+                FURI_LOG_W(
+                    APP_NAME,
+                    "An error occurred during sensor initialization %s",
+                    app->sensors[i]->name);
+                result = false;
+            }
+        }
+    }
+    return result;
 }

+ 35 - 1
interfaces/Sensors.h

@@ -3,12 +3,21 @@
 #include <furi.h>
 #include <input/input.h>
 
+//Статусы опроса датчика
+typedef enum {
+    UT_OK, //Всё хорошо, опрос успешен
+    UT_TIMEOUT, //Датчик не отозвался
+    UT_EARLYPOOL, //Опрос раньше положенной задержки
+    UT_BADCRC, //Неверная контрольная сумма
+    UT_ERROR, //Прочие ошибки
+} UnitempStatus;
+
 //Типы датчиков
 typedef enum {
     DHT11,
     DHT12_1W,
     DHT12_I2C,
-    DHT20,
+    DHT20, //AM2108
     DHT21, //AM2301
     DHT22, //AM2302
     AM2320_1W,
@@ -51,6 +60,8 @@ typedef struct {
 
     //Тип датчика
     SensorType type;
+    //Интерфейсы подключения
+    Interface interface;
     //Экземпляр датчика
     void* instance;
 } Sensor;
@@ -71,4 +82,27 @@ const char* unitemp_getSensorTypeName(SensorType st);
  */
 const GPIO* unitemp_getGPIOFormInt(uint8_t name);
 
+/**
+ * @brief Выделение памяти под датчик
+ * 
+ * @param name Имя датчика
+ * @param st Тип датчика
+ * @return Указатель на датчик
+ */
+Sensor* unitemp_sensor_alloc(char* name, SensorType st);
+
+/**
+ * @brief Инициализация загруженных датчиков
+ * 
+ * @return Истина если всё прошло успешно
+ */
+bool unitemp_sensors_init(void);
+
+/**
+ * @brief Деинициализация загруженных датчиков
+ * 
+ * @return Истина если всё прошло успешно
+ */
+bool unitemp_sensors_deInit(void);
+
 #endif

+ 19 - 12
unitemp.c

@@ -1,9 +1,12 @@
 #include "unitemp.h"
 #include "interfaces/OneWire.h"
+#include "interfaces/Sensors.h"
+
+#include <furi_hal_power.h>
 
 /* Статические переменные */
 //Данные приложения
-static Unitemp* app;
+Unitemp* app;
 
 /**
  * @brief Функция загрузки датчиков с SD-карты
@@ -18,17 +21,16 @@ bool unitemp_loadSensors() {
     memset(app->sensors, 0, sizeof(app->sensors));
 
     //Типа загружен датчик DHT11 на порте 10
-    app->sensors[app->sensors_count] = (Sensor){
-        .name = "DHT11",
-        .type = DHT11,
-        .instance = &(OneWireSensor){.interface = ONE_WIRE, .gpio = unitemp_getGPIOFormInt(10)}};
+    app->sensors[app->sensors_count] = unitemp_sensor_alloc("DHT11", DHT11);
+
+    ((OneWireSensor*)(app->sensors[app->sensors_count]->instance))->gpio =
+        unitemp_getGPIOFormInt(10);
     app->sensors_count++;
 
     //Типа загружен датчик DHT21 на порте 2
-    app->sensors[app->sensors_count] = (Sensor){
-        .name = "DHT21",
-        .type = DHT21,
-        .instance = &(OneWireSensor){.interface = ONE_WIRE, .gpio = unitemp_getGPIOFormInt(2)}};
+    app->sensors[app->sensors_count] = unitemp_sensor_alloc("DHT21", DHT21);
+    ((OneWireSensor*)(app->sensors[app->sensors_count]->instance))->gpio =
+        unitemp_getGPIOFormInt(2);
     app->sensors_count++;
 
     return true;
@@ -191,6 +193,7 @@ static bool unitemp_loadSettings(void) {
         //Автоматическое управление
         notification_message(app->notifications, &sequence_display_backlight_enforce_auto);
     }
+    app->settings.lastOTGState = furi_hal_power_is_otg_enabled();
 
     FURI_LOG_I(APP_NAME, "Settings have been successfully loaded\r\n");
     return true;
@@ -250,6 +253,8 @@ int32_t unitemp_app() {
     unitemp_loadSettings();
     //Загрузка датчиков из SD-карты
     unitemp_loadSensors();
+    //Инициализация датчиков
+    unitemp_sensors_init();
 
     while(1) {
         FURI_LOG_D(APP_NAME, "Sensors values:");
@@ -257,14 +262,16 @@ int32_t unitemp_app() {
             FURI_LOG_D(
                 APP_NAME,
                 "%s: %2.1f*C/%d%%",
-                app->sensors[i].name,
-                (double)app->sensors[i].temp,
-                (uint8_t)app->sensors[i].hum);
+                app->sensors[i]->name,
+                (double)app->sensors[i]->temp,
+                (uint8_t)app->sensors[i]->hum);
         }
 
         furi_delay_ms(1000);
     }
 
+    //Деинициализация датчиков
+    unitemp_sensors_deInit();
     //Освобождение памяти
     unitemp_free();
     //Выход

+ 5 - 2
unitemp.h

@@ -38,14 +38,16 @@ typedef struct {
     //Единица измерения температуры
     //Ложь - градусы Цельсия, истина - Фарeнгейты
     measureUnit unit;
+    //Последнее состояние OTG
+    bool lastOTGState;
 } UnitempSettings;
 
 //Основная структура плагина
 typedef struct {
     //Основные настройки
     UnitempSettings settings;
-    //Список датчиков
-    Sensor sensors[MAX_SENSORS];
+    //Список указателей на датчики
+    Sensor* sensors[MAX_SENSORS];
     //Количество загруженных датчиков
     size_t sensors_count;
 
@@ -59,4 +61,5 @@ typedef struct {
 
 /* Объявление прототипов функций */
 
+extern Unitemp* app;
 #endif