Подключение к Arduino датчиков DS18B20, DHT22, BMP180. Подключение BMP180 датчик давления и температуры к Arduino Алгоритм получения данных
#include
Всем доброго времени суток, ну что же... просто начнем!!! Эта статья о подключении датчика барометрического давления BMP180 к одноплатному компьютеру Arduino Uno , но не так то всё просто, как хотелось бы на первый взгляд. Выводить измеренные и преобразованные значения температуры мы будем на 7-ми сегментный дисплей на базе драйвера MAX7219 . И выводиться они будут в качестве бегущей строчки из двух преобразованных единиц измерения - это градусы Цельсия и градусы Фаренгейта.
Датчик BMP180 является не только датчиком барометрического давления, но и высокоточным датчиком температуры. Это очень чувствительный прибор, в конце статьи будет показано обзорное видео, посмотрев которое, можно будет убедиться насколько он чувствителен. Ну а далее, можно привести характеристики датчика BMP180 :
- Напряжение питания 3.3 вольт
- Потребляемый ток 5 мКА при частоте опроса 1 Hz
- Интерфейс подключения - I2C
- Разброс точности по измеренному давлению +-0.12 hPa (+-1 метр по высоте)
- Диапазон измерения температуры от -40*С до +85*С
- Диапазон измерения давления: от 300 до 1100 hPа
Пришло время подключить датчик к плате Arduino Uno , но так как у нас замеренные и преобразованные значения будут выводиться на 7-ми сегментный дисплей, то на нижеследующей схеме мы покажем полное подключение всех приборов, а также распиновку датчика BMP180 :
В общем то в схеме подключения нет ничего сложного, всё видно и понятно, следующим шагом перейдем к написанию скетча. Несколько важных моментов в реализации визуализации измеренных и преобразованных значений:
- Выводить на дисплей только преобразованные значения температуры (ниже описывается почему)
- Значения температуры должны быть реализованы с десятыми долями градуса(как это видно на картинке превью)
- Реализовать визуализацию в виде бегущей строки
- Обязательно наличие диагностических сообщений о состоянии датчика при включении и инициализации
- Используем библиотеку для работы с датчиком
Почему же всё таки выводить только значения температуры... Конечно, хотелось бы охватить полностью все возможности датчика BMP180 , но для визуализации на 7-ми сегментном дисплее, потребуется задействовать более сложные символы для отображения в сообщениях "бегущей строки", чем те которые можно реально создать используя для модулей визуализации данного типа. Поэтому было решено отображать только преобразованные значения температуры, но и вообще в целом, обычно редко кто смотрит на показания атмосферного давления когда к примеру собирается на прогулку. И всё же - если кто-то захочет более тонко изучить работу с датчиком BMP180, то в подключаемой библиотеке есть два примера, которые могут более детально разъяснить как получать и преобразовывать давление и температуру при помощи данного датчика.
В итоге, был создан вот такой скетч, с комментариями разработчика:
#include "SFE_BMP180.h" #include "Wire.h" #include "LedControl.h" //Прототип функции для прокрутки сообщения msgScrolling() void msgScrolling(byte msg, int msgSize, int dScroll); //Прототип функции по обработке данных температуры //и подготовке сообщения void TmsgPreparation(double value, bool degree); //Создаём объект LC класса LedControl для работы с дисплеем LedControl LC = LedControl(12, 11, 10, 8); //Создаём объект BMP180Sensor класса SFE_BMP180 для работы с датчиком SFE_BMP180 BMP180Sensor; //Время задержки отрисовки символов при прокрутке const int delayScrolling = 300; //Сообщение "Инициализация датчика успешна" byte msgInitSuccess = {91, 79, 21, 91, 29, 5, 16, 21, 16, 15, 0, 91, 28, 13, 13, 79, 91, 91}; //Сообщение "Инициализация датчика безуспешна" byte msgInitFail = {91, 79, 21, 91, 29, 5, 16, 21, 16, 15, 0, 71, 119, 48, 14}; //Массив численных символов без точки byte Digit = {126, 48, 109, 121, 51, 91, 95, 112, 127, 123}; //Массив численных символов с точкой byte pDigit = {254, 176, 237, 249, 179, 219, 223, 240, 255, 251}; //Символьные знаки byte deg = 99; //Символ "градуса" byte C = 78; //Символ "С" - Цельсий byte F = 71; //Символ "F" - Фаренгейт byte S = 1; //Символ "-" - знак минуса(если измеренное значение ниже нуля) void setup() { //Устройство(7-ми сегментный дисплей) выводим из спящего режима LC.shutdown(0, false); //Установить яркость дисплея на 8 //Всего возможных режимов яркости от 0 до 15 LC.setIntensity(0, 8); //Очистить дисплей LC.clearDisplay(0); //Инициализация датчика на шине I2C if(BMP180Sensor.begin()) { //Сообщение на прокрутку - инициализация датчика успешна msgScrolling(msgInitSuccess, sizeof(msgInitSuccess), delayScrolling); } else { while(true) { //Сообщение на прокрутку - инициализация датчика безуспешна msgScrolling(msgInitFail, sizeof(msgInitFail), delayScrolling); } } } void loop() { char status; double T, tCelsius, tFahrenheit; //Начинаем измерения температуры //функция startTemperature() возвращает количество миллисекунд //с начала процесса измерения, если процесс измерения прошел правильно, //сохраним это значение в переменную status //Если функция возвращает 0 то процесс измерения прошел неправильно status = BMP180Sensor.startTemperature(); if(status != 0) { //Подождать то самое количество миллисекунд delay(status); //Получить замеренное и обработанное значение температуры //в градусах Цельсия, и сохранить в переменной Т //функция getTemperature() возвращает 1 если вызов её //прошел успешно, и 0 если функция не смогла инициализировать //переменную Т измеренным значением status = BMP180Sensor.getTemperature(T); if(status != 0) { //Присвоение значения переменным //и обработка градуировок для шкалы Фаренгейта tCelsius = T; tFahrenheit = (9.0 / 5.0) * T + 32.0; } } //Обработка значения и //подготовка сообщения - температура TmsgPreparation(tCelsius, false); TmsgPreparation(tFahrenheit, true); } //Здесь собственно сама функция для прокрутки готовых сообщений //справа - налево /* * Параметры: * byte msg - указатель на массив символьных данных * int msgSize - размер массива символьных данных * int dScroll - задержка прокрутки(сдвига сообщения влево) * в миллисекундах */ void msgScrolling(byte msg, int msgSize, int dScroll) { for(int i = 0; i < 8 + msgSize; i ++) { for(int n = i, j = 0; n >= 0, j < msgSize; n --, j ++) { LC.setRow(0, n, msg[j]); LC.setRow(0, n - 1, B00000000); } delay(dScroll); } } /* * Здесь функция подготовки сообщения, прежде чем оно будет выведено * для прокрутки на дисплее. Параметры: * double value - значение температуры двойной степени точности * bool degree - флаг для определения шкалы градуирования * если false - значит градусы Цельсия * если true - значит градусы Фаренгейта */ void TmsgPreparation(double value, bool degree) { //Приводим к абсолютному значению и сохраняем в переменной T //Это унифицирует значение и сократит код функции вдвое double T = abs(value); //Здесь значение фильтруется, если есть отклонение на пол градуса //от нуля то всё равно формировать сообщение что температура равна 0 //Итак, если замеренная температура меньше 0.5 то ставим 0 if(T < 0.5) { //Резервируем символьный массив на три символа byte preMsg; //Первый символ - это естественно 0 preMsg = Digit; //Второй символ - это сгенерированный символ "градус" preMsg = deg; //Проверка флага градуировки if(degree) { //Если true - то это градусы Фаренгейта //и третий символ в массиве будет содержать //сгенерированный символ F(код 71) preMsg = F; } else { //Иначе, если true - то это градусы Цельсия //и третий символ в массиве будет содержать //сгенерированный символ С(код 78) preMsg = C; } //Отправляем указатель на проинициализированный символьный массив preMsg //в качестве первого параметра функции для прокрутки сообщений //второй параметр - это размер символьного массива preMsg //третий параметр - задержка сдвига(прокрутки влево) в миллисекундах msgScrolling(preMsg, sizeof(preMsg), delayScrolling); //После прокрутки сообщения покинуть тело функции return; } //Если больше 0.5 но меньше 1 if(T < 1) { byte preMsg; preMsg = pDigit; preMsg = Digit; preMsg = deg; if(degree) { preMsg = F; } else { preMsg = C; } //Здесь нужно знать показания температуры //Отрицательные или положительные, //если отрицательные - добавить отрисовку знака минус if(value < 0) { byte rdyMsg; //В первый байт массива символов сообщения //записываем знак rdyMsg = S; //Далее - слияние массивов в готовое сообщение for(int i = 1; i < sizeof(rdyMsg); i ++) { // rdyMsg[i] = preMsg; } msgScrolling(rdyMsg, sizeof(rdyMsg), delayScrolling); return; } else { msgScrolling(preMsg, sizeof(preMsg), delayScrolling); return; } } //Если больше 1 но меньше 10 if(T < 10) { byte preMsg; preMsg = pDigit; preMsg = Digit; preMsg = deg; if(degree) { preMsg = F; } else { preMsg = C; } if(value < 0) { byte rdyMsg; //В первый байт массива символов сообщения //записываем знак rdyMsg = S; //Далее - слияние массивов в готовое сообщение for(int i = 1; i < sizeof(rdyMsg); i ++) { // rdyMsg[i] = preMsg; } msgScrolling(rdyMsg, sizeof(rdyMsg), delayScrolling); return; } else { msgScrolling(preMsg, sizeof(preMsg), delayScrolling); return; } } //Если больше 10 но меньше 100 if(T < 100) { byte preMsg; preMsg = Digit; preMsg = pDigit; preMsg = Digit; preMsg = deg; if(degree) { preMsg = F; } else { preMsg = C; } if(value < 0) { byte rdyMsg; //В первый байт массива символов сообщения //записываем знак rdyMsg = S; //Далее - слияние массивов в готовое сообщение for(int i = 1; i < sizeof(rdyMsg); i ++) { // rdyMsg[i] = preMsg; } msgScrolling(rdyMsg, sizeof(rdyMsg), delayScrolling); return; } else { msgScrolling(preMsg, sizeof(preMsg), delayScrolling); return; } } //Если больше 100 но меньше 1000 if(T < 1000) { byte preMsg; preMsg = Digit; preMsg = Digit; preMsg = pDigit; preMsg = Digit; preMsg = deg; if(degree) { preMsg = F; } else { preMsg = C; } if(value < 0) { byte rdyMsg; //В первый байт массива символов сообщения //записываем знак rdyMsg = S; //Далее - слияние массивов в готовое сообщение for(int i = 1; i < sizeof(rdyMsg); i ++) { // rdyMsg[i] = preMsg; } msgScrolling(rdyMsg, sizeof(rdyMsg), delayScrolling); return; } else { msgScrolling(preMsg, sizeof(preMsg), delayScrolling); return; } } }
Еще хотелось бы сказать, что в стандартной библиотеке LedControl не было найдено функций прокрутки, может быть мы будем теми кто дополнит эту библиотеку? Что же, всё зависит от пожеланий наших посетителей, комментируйте, пробуйте, задавайте вопросы... Ждем ваших отзывов. Видео работы скетча также прилагается к этой статье, смотрим результаты работы скетча:
Барометр — это устройство, которое измеряет атмосферное давление. То есть давление воздуха, который давит на нас со всех сторон. Еще со школы мы знаем, что первый барометр представлял собой тарелку с ртутью, и перевернутой пробиркой в ней. Автором этого устройства был Эванджели́ста Торриче́лли — итальянский физик и математик. Снять показания ртутного барометра можно так же просто, как и показания спиртового термометра: чем давление снаружи колбы больше, тем выше столбик ртути внутри неё. Пары ртути, как известно, весьма ядовиты.
Позже, появился более безопасный прибор — барометр-анероид. В этом барометре ртуть была заменена на гофрированную коробку из тонкой жести, в которой создано разрежение. Под воздействием атмосферы, коробочка сжимается и через систему рычагов поворачивает стрелку на циферблате. Вот так выглядят эти два барометра. Слева — анероид, справа — барометр Торричелли.
Зачем нам может понадобиться барометр? Чаще всего, этот прибор используют на летательных аппаратах для определения высоты полета. Чем выше аппарат поднимается над уровнем моря, тем меньшее давление испытывает бортовой барометр. Зная эту зависимость, легко определить высоту.
Другой распространенный вариант использования — самодельная погодная станция. В этом случае мы можем использовать известные зависимости грядущей погоды от атмосферного давления. Помимо барометра, на такие станции ставят датчики влажности и температуры.
Электронный барометр
Такие громоздкие барометры мы не сможем использовать в робототехнике. Нам нужен миниатюрный и энергоэффективный прибор, который легко подключается к той же Ардуино Уно. Большинство современных барометров делают по технологии МЭМС, так же как и гиротахометры с акселерометрами. МЭМС барометры основаны на пьезорезистивном, либо на тензометрическом методе, в которых используется эффект изменения сопротивления материала под действием деформирующих сил.
Если открыть корпус МЭМС барометра, можно увидеть чувствительный элемент (справа), который находится прямо под отверстием в защитном корпусе прибора, и плату управления (слева), которая осуществляет первичную фильтрацию и преобразование измерений.
Датчики BMP085 и BMP180
К самым доступным датчикам давления, которые часто используются полетных контроллерах и в разного рода самодельных электронных устройствах, можно отнести датчики компании BOSH: BMP085 и BMP180. Второй барометр более новый, но полностью совместимый со старой версией.
Немного важных характеристик BMP180:
- диапазон измеряемых значений: от 300 гПа до 1100 гПа (от -500м от +9000м над уровнем моря);
- напряжение питания: от 3.3 до 5 Вольт;
сила тока: 5 мкА при скорости опроса — 1 Герц; - уровень шума: 0.06 гПа (0.5м) в грубом режиме (ultra low power mode) и 0.02 гПа (0.17м) а режиме максимального разрешения (advanced resolution mode).
Теперь подключим этот датчик к контроллеру, и попробуем оценить атмосферное давление.
Подключение BMP180
Оба датчика имеют I2C интерфейс, так что их без проблем можно подключить к любой платформе из семейства Ардуино. Вот как выглядит таблица подключения к Ардуино Уно.
BMP 180 | GND | VCC | SDA | SCL |
Ардуино Уно | GND | +5V | A4 | A5 |
Принципиальная схема
Внешний вид макета
Программа
Для работы с датчиком нам понадобится библиотека: BMP180_Breakout_Arduino_Library
Скачиваем её из репозитория, и устанавливаем в Arduino IDE. Теперь все готово для написания первой программы. Попробуем получить сырые данные из датчика, и вывести их в монитор COM порта.
#include
Процедура получения заветного давления из датчика не такая тривиальная, и состоит из нескольких этапов. В упрощенном виде алгоритм выглядит так:
- запрашиваем у барометра показания встроенного датчика температуры;
- ждем время A, пока датчик оценивает температуру;
- получаем температуру;
- запрашиваем у барометра давление;
- ждем время B, пока датчик оценивает давление;
- получаем значение давления;
- возвращаем значение давления из функции.
Время B зависит от точности измерений, которая задается в функции startPressure . Единственный аргумент этой функции может принимать значения от 0 до 3, где 0 — самая грубая и самая быстрая оценка, 3 — самая точная оценка давления.
Загружаем программу на Ардуино Уно, и наблюдаем поток измерений атмосферного давления. Попробуем поднять датчик над головой, и опустить до уровня пола. Показания будут немного меняться. Осталось только разобраться, как нам преобразовать эти непонятные числа в высоту над уровнем моря.
Преобразование давления в высоту над уровнем моря
Датчик BMP180 возвращает величину давления в гектопаскалях (гПа). Именно в этих единицах принято измерять атмосферное давление. 1 гПа = 100 Паскалей. Известно, что на уровне моря давление в среднем составляет 1013 гПа, и каждый дополнительный метр над уровнем моря будет уменьшать это давление всего на 0.11 гПа (примерно).
Таким образом, если мы вычтем из результата функции getPressure число 1013, и разделим оставшуюся разность на 0.11, то мы получим значение высоты над уровнем моря в метрах. Вот так изменится наша программа:
Void loop(){ double P, Alt; P = getPressure(); Alt = (P - 1013)/0.11; Serial.println(Alt, 2); delay(100); }
В действительности, давление зависит от высоты над уровнем моря нелинейно, и наша формула годится лишь для высот на которых мы с вами обычно живем. Благо, человечеству известная более точная зависимость давления от высоты, которую мы можем применить для получения более точных результатов.
Здесь p — измеренное в данной точке давление, p0 — давление относительно которого идет отсчет высоты.
В библиотеке SFE_BMP180 уже есть функция, которая использует указанную. формулу для получения точной высоты. Используем её в нашей программе.
#include
Я не стал полностью копировать функцию getPressure, чтобы сохранить читабельность текста.
В программе появилась еще одна переменная P0 — это давление, которое мы измерим на старте программы. В случае летательного аппарата, P0 будет давлением на взлетной площадке, относительно которой мы начнем набор высоты.
Визуализация
Теперь попробуем отобразить показания давления в программе SFMonitor , и посмотрим как меняется давление при движении датчика на высоту 2 метра.
Static const byte PACKET_SIZE = 1;
static const byte VALUE_SIZE = 2;
static const boolean SEPARATE_VALUES = true;
#include
В результате работы программы получим график давления в Паскалях:
Заключение
Как мы уяснили из урока, определение высоты над уровнем моря не такая тривиальная задача. Мало того, что давление зависит от высоты нелинейно, так еще картину портят различные внешние факторы. Например, давление у нас дома постоянно меняется с течением времени. Даже за несколько минут, высота измеренная нашим прибором может варьироваться в диапазоне 0.5 — 1 метра. Температура так же сильно влияет на качество измерений, поэтому нам приходится учитывать её при расчете давления.
Для летательных аппаратов рекомендуется использовать датчики повышенной точности, такие как MS5611. У этого барометра точность измерений может достигать 0,012 гПа, что в 5 раз лучше, чем у BMP180. Также, для уточнения барометрической высоты полета применяют координаты GPS.
Успехов в наблюдении за атмосферой! 🙂
Апрель 2, 2015
Датчик атмосферного давления BMP180 от компании Bosch является более экономным в плане электропитания и более точным чем его предшественник .
Датчик BMP180
Основные характеристики датчика BMP180:
- Диапазон измерения давления: 300 – 1100hPa
- Напряжение питания: от 3.3 и 5V
- Низкое энергопотребление: 3 мкА (режим ультра-низкого энергопотребления)
- Точность: режим пониженного энергопотребления, разрешение 0.06hPa (0,5 м)
- Высокий линейный режим с разрешением 0.02hPa
- Подключение: протокол связи I2C
- Возможность измерения температуры в диапазоне -40 … +85 ° C
- Время отклика: 5ms
- Ток в режиме ожидания: 0,1 мкA
- VCC – для подключения 5в питания
- GND – для подключения к минусу (GND)
- SCL и SDA – для подключения к шине I2C
- 3.3 – для подключения 3.3в питания
Купить датчик BMP180:
Библиотеки для датчика BMP180:
Для работы с датчиком BMP180 используются библиотеки которые предназначены для датчика BMP085 .
Библиотека для работы с датчиком атмосферного давления BMP085 от Adafruit
Библиотека для работы с датчиком давления BMP085
Какую именно библиотеку использовать для работы с датчиком решать Вам. Обзор библиотеки BMP085 я делал ранее в статье
Для примера я буду использовать библиотеку от Adafruit. Для начала запустим тестовый скетч из библиотеки и откроем монитор порта…
Как мы видим у нас есть:
- Temperature = 27.40 *C — Температура в градусах Цельсия
- Pressure = 97726 Pa — Атмосферное давление в Паскалях
- Altitude = 303.19 meters — Высота в метрах
- Pressure at sealevel (calculated) = 97735 Pa — Атмосферное давление в Паскалях (относительно уровня моря (расчетная))
- Real altitude = 317.47 meters — Реальная высота (расчетная)
Настройка и калибровка датчика BMP180
Хочу обратить Ваше внимание на то, что расчетные данные не точные, и они задаются в скетче.
Информация
Мы можем получить более точное измерение высоты. Если мы знаем, текущее давление над уровнем моря для наших координат, которое будет меняться в зависимости от погодных условий и тому подобное. Если это 1015 миллибар, то значение равно 101 500 Па.
Теперь узнаем нашу реальную высоту над уровнем моря с помощью карт от Google, для этого перейдем по ссылке . В окне с картой от Google находим наше место пребывания и кликаем левой кнопкой мышки, для установки метки на карте.
Координаты моего местоположения с значениями высоты
Как видим высота над уровнем моря 203 м, но я нахожусь на 3 этаже, значит прибавим еще 7 м и получим высоту 210 метров (приблизительно) и запомним ее. Теперь переходим к скетчу и значение с отображением данных атмосферного давления в Pa переводим в мм.рт.ст (значение делим на 133.3) и меняем отображение “Pa” на “мм”.
code
Arduino
Serial.print("Pressure = "); Serial.print(bmp.readPressure()/133.3); Serial.println(" mm");
Serial . print ("Pressure = " ) ; Serial . print (bmp . readPressure () / 133.3 ) ; Serial . println (" mm" ) ; |
и еще тут
code
Arduino
Serial.print("Pressure at sealevel (calculated) = "); Serial.print(bmp.readSealevelPressure()/133.3); Serial.println(" mm");
Serial . print ("Pressure at sealevel (calculated) = " ) ; Serial . print (bmp . readSealevelPressure () / 133.3 ) ; Serial . println (" mm" ) ; |
Снова загружаем наш скетч в плату и смотрим что у нас в мониторе порта