унифицированный драйвер для датчиков давления

ji231
Offline
Зарегистрирован: 13.01.2013

Пробую баловаться с разными датчиками давления BMP085/BMP180, BMP280, MS5611 

в разных скетчах разные датчики, разные библиотеки. Но в общем-то почти одно и то же.

Сначала инициализация, считывание констант.

Потом по мере необходимости считываем давление, температуру.

Используя их вычисляем высоту над уровнем моря. И даже скорость изменения высоты.

замумукался подгонять скетчи для другого датчика.

Встречались ли кому унифицированные драйвера? Существееное здесь - одинаковые методы для разных моделей.

Тогда можно  попробовать определить тип датчика, создать объект и далее уже по тексту использовать одни и те же методы для разных датчиков.

alex_r61
Offline
Зарегистрирован: 20.06.2012

Adafruit Unified Sensor Driver https://github.com/adafruit/Adafruit_Sensor

Kurzenev
Offline
Зарегистрирован: 17.09.2014

Датчиков давления там всего два+ BME280.

Явно не универсальное решение.

sadman41
Offline
Зарегистрирован: 19.10.2016

У BMP180 и BMP280 разные способы вычислений метрик. MS5611 вообще отличается от бошевских, полагаю. Сомневаюсь, что кому-то специально вперлось писать библиотеку для того, чтобы их однотипно обрабатывать. Потому как в одной системе эти датчики наврядли встретятся и смысла лепить всё в кучу - ноль целых ноль десятых.

b707
Онлайн
Зарегистрирован: 26.05.2017

ji231 пишет:

Пробую баловаться с разными датчиками давления BMP085/BMP180, BMP280, MS5611 . В разных скетчах разные датчики, разные библиотеки. Но в общем-то почти одно и то же. Сначала инициализация, считывание констант. Потом по мере необходимости считываем давление, температуру. Используя их вычисляем высоту над уровнем моря. И даже скорость изменения высоты.

Тогда можно  попробовать определить тип датчика, создать объект и далее уже по тексту использовать одни и те же методы для разных датчиков.

Мне кажется, что вам самое милое дело написать подобный драйвер самому.  Судя по написанному выше вы уже половину пути прошли, делайте базоавый класс "датчик давления" и потом производные для каждого типа. 

ji231
Offline
Зарегистрирован: 13.01.2013

sadman41 пишет:
У BMP180 и BMP280 разные способы вычислений метрик. MS5611 вообще отличается от бошевских, полагаю.

Да, это так. Но на "выхлопе" нужны около 3х:

Init

GetPressure

GetTemperature

GetAltitude

Крайний, возможно, вычисляется по общей для всех типов формуле.

В разных библиотеках разных датчиков - разные:

порядок и типы входных параметров, разное их количество,

некоторые еще и используют глобальные переменные с  разными типами

Пока что от самосборки останавливает недостаток СПОКОЙНОГО времени, чтоб все это "зарисовать", сравнить, решить к какому общему интерфейсу привести. Но придется. )))

А при использовании - определяем что за датчик и делаем привязку этих публичных процедур(методов)  к конкретным для нужного типа датчика.

Что-то похожее из искомого делается (или делалось) в проекте полетного контроллера baseflight (и его клонов)

Uni - библиотеку от фруктов Ада смотрел, но там не нашел всех этих манипуляций с чтением констант и вычислениями давления.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Если зачать все классы от одного родителя, у которого будет виртуальный метод, допустим, Read(), который и будет отвечать за реальное чтение железа разных даччиков, то получение вот этого 

ji231 пишет:

GetPressure

GetTemperature

GetAltitude

получится автоматом.  Желательно, виртуалить и Init()

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

живой пример, давно так сделал, наследую все сенсоры от этого класса, от фоторезистора до 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();  

	}


};
DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

вот например, унаследованный от него 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 &);

За очередь сапщений - см. на моём гитхабе. Там, правда устаревшая версия, но идея та же. 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Хотя, правда, чо это я...

ji231
Offline
Зарегистрирован: 13.01.2013

DetSimen пишет:
Хотя, правда, чо это я...

 

)))) Есть что "прикинуть"