Продвинутая метеостанция v2.0: мониторинг температуры, давления, влажности и высоты в реальном времени
Постройте компактную метеостанцию, точно измеряющую температуру, давление, влажность и высоту прямо в вашем жилом пространстве.
История
Используя Adafruit Starter Pack для Windows 10 IoT Core на Raspberry Pi 2, этот проект демонстрирует, как подключить датчик BME280 (или BMP280) для чтения экологических данных и публикации их в облачный сервис.
Если у вас BMP280, следуйте гайду Weather Station v1: Weather Station v1.
Железо
Подключите Raspberry Pi 2 к макетной плате и соедините датчик BME280 согласно Fritzing-диаграмме в разделе «Схемы» ниже.
Софт
Скачайте стартовый код с GitHub – ms-iot/adafruitsample. Мы пройдёмся по добавке кода для общения с датчиком и публикации показаний.
Откройте Lesson_203v2\StartSolution\lesson_203v2.sln и редактируйте mainpage.xaml.cs.
Полностью готовая версия доступна в Lesson_203v2\FullSolution\lesson_203v2.sln.
MainPage.xaml.cs
Добавьте ссылку на класс BME280:
public sealed partial class MainPage : Page {
// Создаём объект для нашего класса датчика
BME280 BME280;
Инициализируйте датчик в OnNavigatedTo:
// Создаём объект для нашего класса датчика BME280 = new BME280Sensor(); // Инициализируем датчик await BME280.Initialize();
Далее добавьте код для сбора и логирования данных:
- Создайте переменные для температуры, давления, влажности и высоты, инициализированные нулями.
- Задайте константу давления на уровне моря (по умолчанию 1013.25 гПа).
- Прочитайте четыре измерения десять раз и выведите в консоль отладки.
// Инициализируем их нулями.
float temp = 0;
float pressure = 0;
float altitude = 0;
float humidity = 0;
// Константа давления на уровне моря.
const float seaLevelPressure = 1022.00f;
// Читаем 10 сэмплов данных
for (int i = 0; i < 10; i++) {
temp = await BME280.ReadTemperature();
pressure = await BME280.ReadPreasure();
altitude = await BME280.ReadAltitude(seaLevelPressure);
humidity = await BME280.ReadHumidity();
// Пишем значения в консоль отладки
Debug.WriteLine("Temperature: " + temp.ToString() + " deg C");
Debug.WriteLine("Humidity: " + humidity.ToString() + " %");
Debug.WriteLine("Pressure: " + pressure.ToString() + " Pa");
Debug.WriteLine("Altitude: " + altitude.ToString() + " m");
Debug.WriteLine("\n");
}
BME280.cs
Откройте BME280.cs и добавьте после enum адресов регистров:
// Строка для дружественного имени I2C-шины const string I2CControllerName = "I2C1"; // Создаём I2C-устройство private I2cDevice bme280 = null; // Новые калибровочные данные датчика BME280_CalibrationData CalibrationData; // Флаг инициализации устройства bool init = false;
Расширьте метод Initialize для настройки I2C-соединения:
public async Task Initialize() {
Debug.WriteLine("BME280::Initialize");
try {
I2cConnectionSettings settings = new I2cConnectionSettings(BME280_Address);
settings.BusSpeed = I2cBusSpeed.FastMode;
string aqs = I2cDevice.GetDeviceSelector(I2CControllerName);
DeviceInformationCollection dis = await DeviceInformation.FindAllAsync(aqs);
bme280 = await I2cDevice.FromIdAsync(dis[0].Id, settings);
if (bme280 == null) {
Debug.WriteLine("Device not found");
}
} catch (Exception e) {
Debug.WriteLine("Exception: " + e.Message + "\n" + e.StackTrace);
throw;
}
}
Добавьте рутину Begin для проверки сигнатуры датчика и загрузки калибровки:
private async Task Begin() {
Debug.WriteLine("BME280::Begin");
byte[] WriteBuffer = new byte[] { (byte)eRegisters.BMP280_REGISTER_CHIPID };
byte[] ReadBuffer = new byte[] { 0xFF };
bmp280.WriteRead(WriteBuffer, ReadBuffer);
Debug.WriteLine("BME280 Signature: " + ReadBuffer[0].ToString());
if (ReadBuffer[0] != BMP280_Signature) {
Debug.WriteLine("BMP280::Begin Signature Mismatch.");
return;
}
init = true;
CalibrationData = await ReadCoefficeints();
await WriteControlRegister();
await WriteControlRegisterHumidity();
}
Помощники контрольных регистров:
private async Task WriteControlRegisterHumidity() {
byte[] WriteBuffer = new byte[] { (byte)eRegisters.BMP280_REGISTER_CONTROLHUMID, 0x03 };
bmp280.Write(WriteBuffer);
await Task.Delay(1);
}
private async Task WriteControlRegister() {
byte[] WriteBuffer = new byte[] { (byte)eRegisters.BMP280_REGISTER_CONTROL, 0x3F };
bmp280.Write(WriteBuffer);
await Task.Delay(1);
}
Утилиты чтения регистров:
private UInt16 ReadUInt16_LittleEndian(byte register) {
UInt16 value = 0;
byte[] writeBuffer = new byte[] { 0x00 };
byte[] readBuffer = new byte[] { 0x00, 0x00 };
writeBuffer[0] = register;
bmp280.WriteRead(writeBuffer, readBuffer);
int h = readBuffer[1] << 8;
int l = readBuffer[0];
value = (UInt16)(h + l);
return value;
}
private byte ReadByte(byte register) {
byte value = 0;
byte[] writeBuffer = new byte[] { 0x00 };
byte[] readBuffer = new byte[] { 0x00 };
writeBuffer[0] = register;
bmp280.WriteRead(writeBuffer, readBuffer);
value = readBuffer[0];
return value;
}
Функции калибровки и компенсации взяты напрямую из даташита BMP280 и уже предоставлены.
Реализуйте ReadTemperature для возврата температуры в градусах Цельсия:
public async Task<float> ReadTemperature() {
if (!init) await Begin();
byte tmsb = ReadByte((byte)eRegisters.BMP280_REGISTER_TEMPDATA_MSB);
byte tlsb = ReadByte((byte)eRegisters.BMP280_REGISTER_TEMPDATA_LSB);
byte txlsb = ReadByte((byte)eRegisters.BMP280_REGISTER_TEMPDATA_XLSB);
Int32 t = (tmsb << 12) + (tlsb << 4) + (txlsb >> 4);
double temp = BMP280_compensate_T_double(t);
return (float)temp;
}
Завершите ReadPreasure (опечатка в оригинале сохранена для совместимости):
public async Task<float> ReadPreasure() {
if (!init) await Begin();
if (t_fine == Int32.MinValue) await ReadTemperature();
byte tmsb = ReadByte((byte)eRegisters.BMP280_REGISTER_PRESSUREDATA_MSB);
byte tlsb = ReadByte((byte)eRegisters.BMP280_REGISTER_PRESSUREDATA_LSB);
byte txlsb = ReadByte((byte)eRegisters.BMP280_REGISTER_PRESSUREDATA_XLSB);
Int32 t = (tmsb << 12) + (tlsb << 4) + (txlsb >> 4);
Int64 pres = BMP280_compensate_P_Int64(t);
return ((float)pres) / 256;
}
Наконец, реализуйте ReadAltitude для расчёта высоты по бариметрической формуле:
public async Task<float> ReadAltitude(float seaLevel) {
if (!init) await Begin();
float pressure = await ReadPreasure();
pressure /= 100;
return 44330.0f * (1.0f - (float)Math.Pow((pressure / seaLevel), 0.1903f));
}
Ваш проект готов к развёртыванию!
Ожидаемый вывод
Temperature: 24.46189 deg C
Humidity: 54.372 %
Pressure: 99738.73 Pa
Altitude: 205.1726 m
Источник: Weather Station V 2.0
Производственный процесс
- DIY солнечная метеостанция на Raspberry Pi
- Сборка уличной метеостанции на Raspberry Pi 2 и ADS‑WS1
- Создание метеостанции на Raspberry Pi с ежедневными email-отчётами о погоде
- Удалённый мониторинг погоды на Raspberry Pi 3 с PubNub
- Интеграция метеостанции с CWOP: практическое руководство
- Weather Monitor — DIY метеостанция на Raspberry Pi с загрузкой в Dropbox
- Компактная метеостанция: Arduino Nano + ESP8266, BMP280, OLED / Nokia 5110 LCD
- Портативная метеостанция на Arduino Nano за $10: DHT22, BMP180 и LCD
- eDOT: точные Arduino-часы и метеостанция с встроенным ИК-пультом
- Метеостанция на Arduino и ThingSpeak: температура и влажность в облаке