унифицированный драйвер для датчиков давления
- Войдите на сайт для отправки комментариев
Сб, 23/05/2020 - 00:01
Пробую баловаться с разными датчиками давления BMP085/BMP180, BMP280, MS5611
в разных скетчах разные датчики, разные библиотеки. Но в общем-то почти одно и то же.
Сначала инициализация, считывание констант.
Потом по мере необходимости считываем давление, температуру.
Используя их вычисляем высоту над уровнем моря. И даже скорость изменения высоты.
замумукался подгонять скетчи для другого датчика.
Встречались ли кому унифицированные драйвера? Существееное здесь - одинаковые методы для разных моделей.
Тогда можно попробовать определить тип датчика, создать объект и далее уже по тексту использовать одни и те же методы для разных датчиков.
Adafruit Unified Sensor Driver https://github.com/adafruit/Adafruit_Sensor
Датчиков давления там всего два+ BME280.
Явно не универсальное решение.
У BMP180 и BMP280 разные способы вычислений метрик. MS5611 вообще отличается от бошевских, полагаю. Сомневаюсь, что кому-то специально вперлось писать библиотеку для того, чтобы их однотипно обрабатывать. Потому как в одной системе эти датчики наврядли встретятся и смысла лепить всё в кучу - ноль целых ноль десятых.
Пробую баловаться с разными датчиками давления BMP085/BMP180, BMP280, MS5611 . В разных скетчах разные датчики, разные библиотеки. Но в общем-то почти одно и то же. Сначала инициализация, считывание констант. Потом по мере необходимости считываем давление, температуру. Используя их вычисляем высоту над уровнем моря. И даже скорость изменения высоты.
Тогда можно попробовать определить тип датчика, создать объект и далее уже по тексту использовать одни и те же методы для разных датчиков.
Мне кажется, что вам самое милое дело написать подобный драйвер самому. Судя по написанному выше вы уже половину пути прошли, делайте базоавый класс "датчик давления" и потом производные для каждого типа.
Да, это так. Но на "выхлопе" нужны около 3х:
Init
GetPressure
GetTemperature
GetAltitude
Крайний, возможно, вычисляется по общей для всех типов формуле.
В разных библиотеках разных датчиков - разные:
порядок и типы входных параметров, разное их количество,
некоторые еще и используют глобальные переменные с разными типами
Пока что от самосборки останавливает недостаток СПОКОЙНОГО времени, чтоб все это "зарисовать", сравнить, решить к какому общему интерфейсу привести. Но придется. )))
А при использовании - определяем что за датчик и делаем привязку этих публичных процедур(методов) к конкретным для нужного типа датчика.
Что-то похожее из искомого делается (или делалось) в проекте полетного контроллера baseflight (и его клонов)
Uni - библиотеку от фруктов Ада смотрел, но там не нашел всех этих манипуляций с чтением констант и вычислениями давления.
Если зачать все классы от одного родителя, у которого будет виртуальный метод, допустим, Read(), который и будет отвечать за реальное чтение железа разных даччиков, то получение вот этого
GetPressure
GetTemperature
GetAltitude
получится автоматом. Желательно, виртуалить и Init()
живой пример, давно так сделал, наследую все сенсоры от этого класса, от фоторезистора до DS18B20, горя не знаю
enum class enSensorState :int8_t { Unknown = -1, Normal = 1, Passive = 1, Underflow = 2, Less = 2, Overflow = 3, More = 3, Active = 4, Error = 15 }; class TCustomSensor : public TClass { protected: enSensorState FSensorState:7; // состояние сенсора bool FChangeStateMessage : 1; // посылать ли сообщение при смене состояния сенсора uint32_t FLastReadTime; // время (millis()), когда сенсор читали последний раз // функция смены состояния сенсора, при реальном изменении шлёт сообщение в очередь // если разрешено их слать void SetSensorState(enSensorState ANewState); void Error(int AErrorCode) override; // вызывается при ошибке сенсора virtual void init(void) = 0; // абстрактная, переопределяемая инициализация сенсора, если нужна virtual void internalRead(void) = 0; // абстрактное чтение железа virtual void Check(void) = 0; // абстрактная проверка, что значения изменились public: uint32_t ReadInterval; // публичное поле, минимальный интервал физического чтения сенсора, по умолчанию 1 секунда TCustomSensor() { FError = false; // пока ошибки нет FSensorState = enSensorState::Unknown; // нужна инициализация, состояние не определено ReadInterval = 1000; // минимальный интервал чтения 1000 мс. FLastReadTime = 0 - ReadInterval - 1; // когда читали в последний раз FChangeStateMessage = true; // слать сообщение при изменении состояния сенсора classname = F("CustomSensor"); // имя класса. храница в PROGMEM } inline enSensorState getState() const; // отдает, кому интересно, состояние сенсора void Read(void) { // одна функция на все виды унвследованных сенсоров, хоть фоторезистор, хоть кнопка, хоть Даллас с BME280 if (FSensorState == enSensorState::Unknown) init(); // Если сенсор неинициализирован, just do it if (isError()) return; // если ошибка, то и читать нехрен uint32_t now = millis(); if (now - FLastReadTime < ReadInterval) return; // железно читаем сенсор, только если прошел мин. интервал для его опроса. Здесь - 1 сек. FLastReadTime = now; // запомним время последнего чтения // здесь чтение железа, внутри вызывается Check(), и если прочитанное значение // поменялось по сравнению с прошлым - шлёцца сообщение об этом // internalRead(); } };вот например, унаследованный от него D18B20
bool ReadData(void) { FOneWire->reset(); FOneWire->write(CMD_SKIP_ROM); FOneWire->write(CMD_READ_RAM); FOneWire->read_bytes(FDallasMemory, DALLAS_MEMORY_SIZE); FOneWire->reset(); startConversion(); uint8_t crc = OneWire::crc8(FDallasMemory, DALLAS_MEMORY_SIZE - 1); return (crc == FDallasMemory[DALLAS_MEMORY_SIZE - 1]); } void internalRead() override { if (ReadData()) { // если прочитали правильно и совпала КС int8_t temp = (FDallasMemory[1] << 4) | (FDallasMemory[0] >> 4); // вычисляем температуру if (temp == FTemperature) return; // если такая же, как была - уходим // если изменилась, запоминаем её и шлём сообщение в очереть // FTemperature = temp; PostMessage(msg_TemperatureChanged, FTemperature); } else // Не совпала контрольная сумма, тоже известим об этом loop() PostMessage(msg_Error, err_OneWire_CRCError); }зато потом в loop() я могу невозбранно писать
void loop(){ Dallas.Read(); Another.Read(); . . NthSensor.Read(); if (Messages.Available()) Dispatch(Messages.GetMessage()); }чтение железа будет происходить не чаще, чем ReadInterval у каждого сенсора, а если значение какого-то из них изменилось, он положит соощение в очередь, которое будет обработано функцией Dispatch(const TMessage &);
За очередь сапщений - см. на моём гитхабе. Там, правда устаревшая версия, но идея та же.
Хотя, правда, чо это я...
)))) Есть что "прикинуть"