31.10.10

Погодная станция на Ардуино

Ну если быть откровенным, то конечно же не погодная станция, а скорее термометр, барометр и гигрометр в одном флаконе.


До погодной станции еще далеко. Пока что просто посмотрим как получать данные с датчиков температуры, давления и влажности.

Итак, в ролях:
  • Arduino Duemillanove
  • BMP085 от Bosch Sensortec - датчик давления и температуры
  • HIH-4030 от Honeywell - датчик влажности

Датчик влажности прост и незамысловат - подаете на него 5 вольт и получаете напряжение, линейно зависящее от влажности.
Датчик давления и температуры сложнее, он подключается по шине I2C и, кроме того,  использует для питания 3.3V.

Итак собираем схему.
Датчик влажности подключаем к земле и питанию, ногу out подключаем к аналоговому входу №0 ардуино.

Датчик давления подключаем к земле и питанию 3.3 вольта, выходы SDA и SLC подключаем к аналоговым входам 4 и 5 соответственно.

Для получения значения влажности нам понадобятся некоторые константы, которые можно найти в даташите на HIH-4030:


static const int offset = 958;
static const int slope_coef = 10;
static const int slope = 307;

offset - напряжение, соответствующее нулевой относительной влажности, а slope - соотношение между напряжением и влажностью, составляющий 30.68 mV. Поскольку я собираюсь использовать только целочисленную арифметику, то slope заведем как 307 и добавим дополнительный делитель 10.

Функция получения относительной влажности будет выглядеть так:


int get_humidity() {
   long voltage = analogRead(0); // получить значение 0..1023
   voltage = voltage * 5000 / 1023; // преобразовать в микровольты
   // вычислим относительную влажность в процентах
   return ((voltage - offset) * slope / slope_coef) / 100;
}

Код для работы с BMP085 я стянул тут. Имейте в виду, у меня этот код не заработал сразу из-за путаницы с использованием типов int, unsigned int и long. Работающий код можно взять из репозитория на bitbucket.org или из zip-файла в конце статьи.

Для удобства все функции для работы с датчиками удобно собрать в библиотеку. Библиотека в IDE Arduino - это папка с файлами, лежащая в каталоге libraries в каталоге arduino. Библиотека содержит как минимум два файла - заголовочный h-файл и cpp-файл с кодом.

Я сделал такой заголовочный файл:


/*
Library of utility classes and functions for Arduino weather station
*/

#ifndef WEATHER_H
#define WEATHER_H

#include "WProgram.h"

// interface for humidity sensor HIH-4030
class Humidity {
  private:
    static const int offset = 958;
    static const int slope_coef = 10;
    static const int slope = 307;

    int pin;
  public:
    Humidity(const int pin = 0);

    // returns relative humidity in percents * 10
    // to get actual humidity delete results by ten
    long get_humidity();

    int get_humidity_int();
};

#define I2C_ADDRESS 0x77
#define DEFAULT_OVERSAMPLING 3

class TemperaturePressure {
  private:
    int i2c_address;
    unsigned char oversampling_setting; //oversamplig for measurement

    static const unsigned char pressure_waittime[];// = { 5, 8, 14, 26 };

    //taken straight from the BMP085 datasheet
    int ac1, ac2, ac3;
    unsigned int ac4, ac5, ac6;
    int b1, b2, mb, mc, md;

    int _temp;
    long _pressure;

    void get_calibration_data();
 
    int read_int_register(unsigned char reg);
    char read_register(unsigned char reg);
    void write_register(unsigned char reg, unsigned char value);

    unsigned int read_ut();
    long read_up();

    void read_temperature_and_pressure();
  public:
    TemperaturePressure();
    TemperaturePressure(const int i2c_address, const int oversampling);

    void read_data_from_sensor();

    int get_temperature();
    long get_pressure();

    long get_pressure_hg();

    void begin();
};

#endif

Как видно, библиотека содержит два класса - Humidity, для работы с датчиком влажности и TemperaturePressure, для работы с датчиком давления и температуры.
Для работы с датчиком давления используется библиотека Wire, которая включена в стандартный набор библиотек Arduino. К сожалению я не понял, как можно задействовать в своей библиотеке стандартные библиотеки ардуино, так что пришлось в программе включать два заголовочных файла - Wire.h и Weather.h

CPP-файл я показывать здесь не буду, чтобы не загромождать все текстом.

Ну и наконец скетч для ардуино, который использует библиотеку Weather:

#include <wire.h>
#include <weather.h>

#define HUMIDITY_PIN 0

Humidity humidity(HUMIDITY_PIN);
TemperaturePressure tempPres;

void setup() {
  Serial.begin(9600);
  Serial.println("Calibrating...");
  tempPres.begin();
  Serial.println("Calibrated");

  // Light the LED when ready
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);
}

void loop() {
  int h = humidity.get_humidity_int();

  tempPres.read_data_from_sensor();
  int t = tempPres.get_temperature();
  float p = tempPres.get_pressure() * 7.5006e-3; // convert to mmHg

  Serial.print(t/10.0);
  Serial.print(";");
  Serial.print(p);
  Serial.print(";");
  Serial.println(h);

  delay(60000);
}

Скетч получает данные о температуре, относительной влажности и давлении и передает их через последовательный порт на десктоп, где простой python-скрипт записывает их в CSV-файл. Из результирующих данных можно, к примеру, построить графики изменения параметров во времени.


Исходники библиотеки и скетча можно скачать отсюда или с помощью Mercurial забрать с bitbucket

30.10.10

Design patterns



Then there was another book that everybody thought was the greatest thing ever in that same period—Design Patterns—which I just thought was crap. It was just like, programming via cut and paste. Rather than thinking through your task you looked through the recipe book and found something that maybe, kinda, sorta felt like it, and then just aped it. That’s not programming; that’s a coloring book. But a lot of people seemed to love it. Then in meetings they’d be tossing around all this terminology they got out of that book. Like, the inverse, reverse, double-back-flip pattern—whatever. Oh, you mean a loop? OK. -- Jamie Zawinski from "Coders at Work". 


Just what I always felt about all this stuff with patterns, but could not express clearly.