Ардуино. Метеостанция на LCD 1602 и DHT11
Ардуино. Метеостанция с дисплеем LCD 1602 и DHT22 После сборки схемы, загрузите в микроконтроллер следующий скетч (здесь ссылка на скачивание архива со скетчем для метеостанции и необходимыми библиотеками). Информация с датчика DHT22 выводиться будет на монитор порта Arduino IDE и на жидкокристаллический дисплей 1602a, для отображения информации использован русский шрифт для LCD и символы (в скетче есть подробные комментарии).
Скетч для метеостанции с DHT11 на Ардуино
#include <Wire.h> // библиотека для протокола IIC #include <LiquidCrystal_I2C.h> // подключаем библиотеку LCD IIC LiquidCrystal_I2C lcd(0x27,20,2); // присваиваем имя lcd для дисплея #include «DHT.h» // подключаем библиотеку для DHT11 DHT dht(2, DHT11); // к какому порту подключаем датчик // создаем символ градуса и присваиваем имя «gradus» byte gradus = { 0b01100,0b10010,0b10010,0b01100,0b00000,0b00000,0b00000,0b00000 }; // создаем русскую букву «П» byte P = { 0b11111,0b10001,0b10001,0b10001,0b10001,0b10001,0b10001,0b00000 }; // создаем русскую букву «У» byte Y = { 0b10001,0b10001,0b10001,0b01111,0b00001,0b00001,0b01110,0b00000 }; // создаем русскую букву «Л» byte L = { 0b00111,0b01001,0b10001,0b10001,0b10001,0b10001,0b10001,0b00000 }; // создаем русскую букву «Ж» byte ZH = { 0b10101,0b10101,0b10101,0b01110,0b10101,0b10101,0b10101,0b00000 }; // создаем русскую букву «Ь» byte znak = { 0b10000,0b10000,0b10000,0b11110,0b10001,0b10001,0b11110,0b00000 }; void setup() { Serial.begin(9600); // запуск последовательного порта lcd.init(); // инициализация LCD дисплея lcd.backlight(); // включение подсветки дисплея lcd.createChar(1, gradus); lcd.createChar(2, P); lcd.createChar(3, Y); lcd.createChar(4, L); lcd.createChar(5, ZH); lcd.createChar(6, znak); } void loop() { // если нужны точные значение, то используйте float, вместо byte byte h = dht.readHumidity(); // считываем значение температуры byte t = dht.readTemperature(); // считываем значение влажности Serial.print(«Temperature: «); Serial.println(t); // отправляем значение температуры на монитор Serial.print(«Humidity: «); Serial.println(h); // отправляем значение температуры на монитор Serial.println(» «); // пустая строка lcd.setCursor(0,0); // ставим курсор на 1 символ первой строки lcd.print(«TEM»); // используем латинские буквы lcd.print(char(2)); // выводим русскую букву «П» lcd.print(«EPAT»); // используем латинские буквы lcd.print(char(3)); // выводим русскую букву «У» lcd.print(«PA: «); // используем латинские буквы lcd.print(t); // выводим значение температуры на LCD lcd.print(char(1)); // выводим знак градуса lcd.setCursor(2,1); // ставим курсор на 3 символ второй строки lcd.print(«B»); // используем латинские буквы lcd.print(char(4)); // выводим русскую букву «Л» lcd.print(«A»); // используем латинские буквы lcd.print(char(5)); // выводим русскую букву «Ж» lcd.print(«HOCT»); // используем латинские буквы lcd.print(char(6)); // выводим русскую букву «Ь» lcd.print(«: «); // используем латинские буквы lcd.print(h); // выводим значение влажности на LCD lcd.print(«%»); // выводим знак процент delay(1000); }
Пояснения к коду:
- в скетче можно использовать до 8 русских букв и символов, при необходимости заменяйте буквы из кириллицы — латинскими буквами;
- скорость обновления данных замените на необходимое значение.
Заключение. Мы рассмотрели, как сделать простую домашнюю метеостанцию на Ардуино c дисплеем 1602а и датчиком температуры и влажности воздуха DHT11. Данный проект можно доработать, добавив к схеме еще больше датчиков для анализа метеоусловий. Также можно сделать беспроводную метеостанцию на Arduino Uno, используя блютуз или радио модули для передачи информации на расстояние.
Что ещё можно сделать?
- Мы установили только сенсор температуры и влажности. Но у Teensy остаётся ещё много свободных ножек, т.ч. можно добавить разных датчиков: освещённости, атмосферного давления, скорости ветра и т.д.
- Teensy прямо на борту имеет часы реального времени (RTC). Для их работоспособности не хватает только кварца. Можно купить кварц на 32,768 КГц в любом магазине радиоэлементов и припаять его. Тогда можно пробуждать Teensy по будильнику RTC. Достоинство в том, что можно будить устройство чаще в те часы, когда нужны более точные показания. Например, в рабочее время будить устройство каждые 5 минут, а в остальное — каждые полчаса.
Подключение датчика bmp180 к Ардуино
Для этого занятия нам потребуется:
- плата Arduino Uno / Arduino Nano / Arduino Mega;
- датчик давления BMP180 (GY-68);
- дисплей LCD 1602;
- провода «папа-мама».
Как подключить датчик давления bmp180 к Arduino
BMP180 (GY-68) | Arduino Uno | Arduino Nano | Arduino Mega |
GND | GND | GND | GND |
VIN | 5V | 5V | 5V |
SDA | A4 | A4 | 20 |
SCL | A5 | A5 | 21 |
Подключение к микроконтроллеру Ардуино осуществляется по интерфейсу I2C. Контакты SCL / SDA и питание модуля выведены на группу контактов. Кроме того, для работы с датчиком потребуется установить библиотеку BMP180 Breakout Arduino Library, которая позволяет упросить работу с модулем. Команды для bmp180 (bmp080) и gy-68 одинаковые, так что библиотека подойдет для всех перечисленных барометров.
Дисплей 16×4 LCD1604
Подробнее о дисплее и работе с ним погуглите «Работа с символьными ЖКИ на базе HD44780». Отметим, что нужно внимательно отнестись к полярности подключения питания к ЖК-индикатору и чтобы напряжение питания было в диапазоне +4,5…5,5 В. Невнимательное отношение к этому может привести к выходу индикатора из строя!
Пин LCD 1604 | Arduino MEGA | Arduino UNO | Описание |
---|---|---|---|
VSS | GND | GND | GND |
VDD | 5 V | 5 V | 4,7 — 5,3V |
RS | 22 | 4 | Высокий уровень означает, что сигнал на выходах DB0—DB7 является данными, низкий — командой |
RW | GND | GND | Определяет направление данных (чтение/запись). Так как операция чтения данных из индикатора обычно бывает невостребованной, то можно установить постоянно на этом входе низкий уровень |
E | 23 | 5 | Импульс длительностью не менее 500 мс на этом выводе определяет сигнал для чтения/записи данных с выводов DB0-DB7, RS и WR |
DB4 | 24 | 8 | Входящие/исходящие данные |
DB5 | 25 | 9 | |
DB6 | 26 | 10 | |
DB7 | 27 | 11 | |
LED A+ | +5V или резистор 220 Ом → +5VLED-A | ||
LED B- | GND | ||
V0 | GND или подстроечник на 10кОм |
Программная инициализация будет выглядеть так:
Температура, влажность DHT11
Подключение датчика температуры и влажности DHT11 (SainSmart). Датчик расположите лицевой стороной вверх, выводы будут описаны слева направо.
DHT11 | Arduino Mega |
---|---|
DATA | Digital pin 2 (PWM) (см. ниже DHTPIN) |
VCC | 3,3—5 В (рекомендуется 5 В, лучше внешнее питание) |
GND | GND |
Программная инициализация
Барометр BMP180
Подключение датчика атмосферного давления BMP180 (барометр) + температура по интерфейсу I2C/TWI.
BMP180 | Arduino Mega |
---|---|
VCC | не подключен |
GND | GND |
SCL | 21 (SCL) |
SDA | 20 (SDA) |
3,3 | 3,3 В |
Для UNO: A4 (SDA), A5 (SCL).
nRF24L01+
Краткие характеристики:
- Диапазон частот 2,401 — 2,4835 Ггц
- 126 каналов. Нулевой канал начинается с 2400 Мгц и далее с шагом 1 Мгц, например 70 канал находится соответственно на 2470 Мгц. При установке скорости передачи 2Mbps занимается ширина канала в 2 Мгц
- Питание 1,9 — 3,6 В (рекомендуется 3,3 В)
Вот распиновка модуля.
Некоторые советуют сразу же припаять керамический конденсатор 100nF (можно 1µF, 10µF) на выводы питания RF для избежания электрических помех.
Распиновка nRF24L01+ (смотреть сверху платы там где чип, пины должны быть внизу) :
пин 2 3,3V | пин 4 CSN | пин 6 MOSI | пин 8 IRQ |
пин 1 GND | пин 3 CE | пин 5 SCK | пин 7 MISO |
Подключение для метеостанции:
Arduino Mega | nRF24L01+ |
---|---|
3,3 В | VCC пин 2 (лучше внешнее питание) |
пин D8 | CE пин 3 (chip enable in) |
SS пин D53 | CSN пин 4 (chip select in) |
SCK пин D52 | SCK пин 5 (SPI clock in) |
MOSI пин D51 | SDI пин 6 (SPI Data in) |
MISO пин D50 | SDO пин 7 (SPI data out) |
IRQ пин 8 (Interrupt output) не подсоединен | |
GND | GND пин 1 (ground in) |
Программирование радиомодуля будет подробно описано в программной части.
ESP8266
Распиновка ESP8266 (смотреть сверху платы там где чипы, пины должны быть внизу):
GND | GPIO2 | GPIO0 | RX |
TX | CH_PD | RESET | VCC |
Подключение ESP8266 для метеостанции:
ESP8266 | Arduino Mega |
---|---|
TX | 10 пин (SoftwareSerial RX) |
RX | 11 пин (SoftwareSerial TX) |
VCC | 3,3 В |
GND | GND |
CH_PD | Через резистор 10К к 3,3 В Arduino |
GPI0 | Необязательно. Через резистор 10К к 3,3 В Arduino |
GPI2 | Необязательно. Через резистор 10К к 3,3 В Arduino |
КДПВ
Центральный блок в сборе. «Материнскую плату» вырезал из картонной коробки из-под обуви и к ней винтиками на 3 прикрутил всё остальное.
Как видим в этом месте всё питание осуществляется от пинов Ардуино, т.е. к блоку питания напрямую ничего не идёт, и пока мощи хватает.
Вроде всё. Ничего не забыл.
Паяйте, соединяйте. В следующей части будет приведен рабочий скетч для центрального блока и наша метеостанция уже что-то покажет.
Исходный код
Код автономной части
- meteo_sensor.ino
-
#include <Arduino.h> #include <SHT1x.h> #include <LowPower_Teensy3.h> #include <ampline.h> // Таймаут между посылками (не более 65535) #define TIMEOUT 60000 // Количество попыток отправки посылки #define ATTEMPTS 3 // Информационный пин передатчика #define RF_PIN 5 // Пины датчика температуры и влажности #define GND1_PIN 10 #define VCC1_PIN 11 #define GND2_PIN 7 #define VCC2_PIN 8 #define DATA_PIN 12 #define CLK_PIN 9 AmperkaLine rf(RF_PIN); SHT1x sht1x(CLK_PIN, DATA_PIN); void loop(void); // Функция усыпления платы. Каждые TIMEOUT секунд // будет вызываться функция loop_func. TEENSY3_LP LP = TEENSY3_LP(); sleep_block_t* LP_config; void sleep_mode(void) { LP_config = (sleep_block_t*)calloc(1,sizeof(sleep_block_t)); // Просыпаться будем по таймеру LP_config->modules = (LPTMR_WAKE); // Задаём таймаут для таймера LP_config->lptmr_timeout = TIMEOUT; // По истечении таймаута будет вызываться функция loop LP_config->callback = loop; LP.Hibernate(LP_config); } // Функция включения периферии void periferial_start(void) { // Включаем линию передачи данных pinMode(RF_PIN, OUTPUT); // Включаем питания и земли датчиков температуры и влажности pinMode(GND1_PIN, OUTPUT); pinMode(GND2_PIN, OUTPUT); pinMode(VCC1_PIN, OUTPUT); pinMode(VCC2_PIN, OUTPUT); digitalWrite(GND1_PIN, LOW); digitalWrite(GND2_PIN, LOW); digitalWrite(VCC1_PIN, HIGH); digitalWrite(VCC2_PIN, HIGH); // Включаем светодиод для индикации передачи pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, HIGH); // Выбираем в качестве опорного напряжения внутренний // источник (=1.2 В) analogReference(INTERNAL); } // Функция выключения периферии void periferial_stop(void) { // Выключаем линию передачи данных pinMode(RF_PIN, INPUT); // Выключаем датчик температуры и влажности pinMode(GND1_PIN, INPUT); pinMode(GND2_PIN, INPUT); pinMode(VCC1_PIN, INPUT); pinMode(VCC2_PIN, INPUT); pinMode(18, INPUT_PULLUP); pinMode(19, INPUT_PULLUP); // Выключаем светодиод digitalWrite(LED_BUILTIN, LOW); } void setup(void) { // Ничего не инициализируем, сразу засыпаем sleep_mode(); } // Эта функция выполняется раз в TIMEOUT секунд void loop(void) { unsigned long msg; byte temp, humidity, voltage; // Включаем периферию periferial_start(); // Подождём, пока включится датчик температуры и влажности delay(30); // Получаем входные данные с сенсоров temp = (byte)(sht1x.readTemperatureC() + 40.)*2; humidity = (byte)sht1x.readHumidity(); voltage = analogRead(A0)4; // Составляем из данных посылку msg = ; msg |= voltage; msg <<= 8; msg |= humidity; msg <<= 8; msg |= temp; // Отправляем несколько раз посылку for(int i = ; i < ATTEMPTS; i++) rf.send(msg); // Выключаем периферию periferial_stop(); // После выхода из функции плата снова уснёт }
Код платы, работающей в помещении
- receiver.ino
-
#include <Arduino.h> #include <SPI.h> #include <Ethernet.h> #include <ampline.h> byte mac = { 0x90, 0xA7, 0xDA, 0x0F, 0xBC, 0x75 }; char server = "narodmon.ru"; EthernetClient client; const int rfpin = 7; AmperkaLine rf(rfpin); void setup(void) { pinMode(rfpin, INPUT); pinMode(6, OUTPUT); Serial.begin(9600); Serial.println("Started."); } void loop(void) { static unsigned long pushtimeout = ; static float temp, humidity, voltage; unsigned long msg; int res; if((res = rf.receive(&msg)) == ) { temp = ((float)(msg&0xFF))2. - 40.; msg >>= 8; humidity = (float)(msg&0xFF); msg >>= 8; voltage = (float)(msg&0xFF) 256. * 1.2 * 10 * 1.1; digitalWrite(6, HIGH); Serial.print("Temp: "); Serial.print(temp); Serial.print(", humidity: "); Serial.print(humidity); Serial.print(", voltage: "); Serial.println(voltage); digitalWrite(6, LOW); } else Serial.println('E'); if(millis() - pushtimeout > 60000*5) { pushtimeout = millis(); Serial.println("Starting Ethernet..."); if (Ethernet.begin(mac) == ) { Serial.println("Failed to configure Ethernet using DHCP"); while(1) { } } delay(1000); Serial.println("connecting..."); if (client.connect(server, 8283)) { Serial.println("connected"); client.println("#90-A7-DA-0F-BC-75#Sensor#55.751775#37.616856#0.0"); client.print("#90A7DA0FBC7501#"); client.print(temp, DEC); client.println("#In"); client.print("#90A7DA0FBC7502#"); client.print(humidity, DEC); client.println("#Humidity"); client.print("#90A7DA0FBC7503#"); client.print(voltage, DEC); client.println("#Voltage"); client.println("##"); } else Serial.println("connection failed"); { unsigned long tm = millis(); while(millis() - tm < 5000) { if (client.available()) { char c = client.read(); Serial.print(c); } } } client.stop(); } }
Код:
Копируем этот код и вставляем в IDE
#include <LCD_1602_RUS.h> // подключаем библиотеку для датчика
LCD_1602_RUS lcd(0x27, 20, 4); // определяем адрес дисплея и его размер
#include <DHT.h> // подключаем библиотеку для датчика
DHT dht(2, DHT11); // сообщаем на каком порту будет датчик
void setup()
{
lcd.init(); // Инициализация дисплея
lcd.backlight(); // Подключение подсветки
lcd.clear(); // Чистим дисплей
dht.begin(); // запускаем датчик DHT11
}
void loop()
{
float h = dht.readHumidity(); // считываем температуру (t)
float t = dht.readTemperature(); // и влажность (h)
lcd.setCursor(0, 0); // Устанавливаем курср на нулевую символ и нулевой строки
lcd.print(«Влажн. :»); // выводим надпись «Влажн.:»
lcd.print(h,1); // выводим значение влажности с одним символом после запятой
lcd.print(» %»); // выволим знак процента
lcd.setCursor(0, 1); // Устанавливаем курср на нулевой символ первой строки
lcd.print(«Темпер.:»); // выводим надпись «Темпер.:»
lcd.print(t,1); // выводим значение влажности с одним символом после запятой
lcd.print(«\337C»); // выволим знак градуса (337 символ в талице) и «С»
delay(2000); // ждём 2000 микросикенд (2 секунды)
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
#include <LCD_1602_RUS.h> // подключаем библиотеку для датчика LCD_1602_RUS lcd(0x27,20,4);// определяем адрес дисплея и его размер #include <DHT.h> // подключаем библиотеку для датчика DHT dht(2,DHT11);// сообщаем на каком порту будет датчик voidsetup() { lcd.init();// Инициализация дисплея lcd.backlight();// Подключение подсветки lcd.clear();// Чистим дисплей dht.begin();// запускаем датчик DHT11 } voidloop() { floath=dht.readHumidity();// считываем температуру (t) floatt=dht.readTemperature();// и влажность (h) lcd.setCursor(,);// Устанавливаем курср на нулевую символ и нулевой строки lcd.print(«Влажн. :»);// выводим надпись «Влажн.:» lcd.print(h,1);// выводим значение влажности с одним символом после запятой lcd.print(» %»);// выволим знак процента lcd.setCursor(,1);// Устанавливаем курср на нулевой символ первой строки lcd.print(«Темпер.:»);// выводим надпись «Темпер.:» lcd.print(t,1);// выводим значение влажности с одним символом после запятой lcd.print(«\337C»);// выволим знак градуса (337 символ в талице) и «С» delay(2000);// ждём 2000 микросикенд (2 секунды) } |
Копируем его в поле для кода IDE:
и жмём загрузить:
Кнопка «загрузить»
Загрузка завершена
Ждём несколько секунд и наша метеостанция работает:
Метеостанция работает
Барометр на Ардуино своими руками
#include <Wire.h> #include <SFE_BMP180.h> SFE_BMP180 pressure; // создаем объект pressure #define ALTITUDE 1655.0 // высота офиса SparkFun, штат Колорадо, в метрах void setup(){ Serial.begin(9600); // запускаем монитор порта pressure.begin(); // запускаем датчик давления } void loop(){ char status; double T,P,p0,a; // для точного измерения, следует знать высоту, на которой производятся замеры // в этом примере используется константа ALTITUDE Serial.println(); Serial.print("provided altitude: "); Serial.print(ALTITUDE,0); Serial.println(" meters"); // перед измерением давления, следует узнать температуру // если запрос успешен, то возвращается время ожидания в миллисекундах // если запрос на измерение температуры не успешен, то возвращается 0 status = pressure.startTemperature(); if (status != 0){ delay(status); // результат измерения температуры сохраняется в переменной T status = pressure.getTemperature(T); if (status != 0){ Serial.print("temperature: "); Serial.print(T,2); Serial.println(" deg C"); // запускаем измерение давления // если запрос успешен, возвращается время ожидания в миллисекундах // если запрос на измерение давления не успешен, возвращается 0 status = pressure.startPressure(3); if (status != 0){ delay(status); status = pressure.getPressure(P,T); if (status != 0){ Serial.print("absolute pressure: "); Serial.print(P,2); Serial.print(" mb, "); Serial.print(P*0.0295333727,2); Serial.println(" inHg"); // датчик bmp180 возвращает абсолютное давление, которое зависит от высоты // параметры: P = абсолютное давление в мб, ALTITUDE = текущая высота в м. // результат: p0 = давление с компенсацией на уровне моря в мбар p0 = pressure.sealevel(P,ALTITUDE); Serial.print("relative (sea-level) pressure: "); Serial.print(p0,2); Serial.print(" mb, "); Serial.print(p0*0.0295333727,2); Serial.println(" inHg"); } else Serial.println("error retrieving pressure measurement\n"); } else Serial.println("error starting pressure measurement\n"); } else Serial.println("error retrieving temperature measurement\n"); } else Serial.println("error starting temperature measurement\n"); delay(5000); }
Пояснения к коду:
- чтобы убрать влияние высоты при измерении атмосферного давления, используйте функцию уровня моря и текущую высоту;
- скачать библиотеку SFE_BMP180.h для работы с датчиком атмосферного давления BMP180 Arduino можно на нашем сайте здесь.
Шаг третий. Подключаем ЖК-экран
Теперь я отучу свою метеостанцию от компьютера: добавлю собственный экранчик и выведу на него температуру в двух шкалах — Цельсия и Фаренгейта.
Из кода программы я уберу команды, которые вызывали последовательный порт и группировали данные для отправки на компьютер.
Вместо них добавлю команды для работы с LED-дисплеем: подключение библиотеки, определение контактов и формирование строк. Первая строка меняться не будет, а во вторую выведу сразу два значения температуры: в градусах Цельсия и Фаренгейта.
У нас получилась простая метеостанция, которая умеет работать самостоятельно и передавать данные на компьютер. Это самый простой кирпичик для создания умного дома. Такие устройства можно использовать для контроля температуры в комнатах и парниках, управления системами отопления и подогрева воды, в качестве противопожарной сигнализации. Всё зависит только от вашей фантазии.
Станция с датчиком давления
Следующая модель будет уметь определять:
- влажность и температуру;
- уровень высоты;
- атмосферное давление.
Компоненты
Для сборки потребуются:
- сенсор DHT22;
- датчик давления BMP180;
- плата Ардуино Нано;
- lcd-экран с блоком I2C;
- резистор 10 кОм;
- плата макетная;
- припой;
- 40-контактный однорядный разъем;
- соединительные провода.
Придется паять и работать с контактами, поэтому также необходим паяльник и плоскогубцы.
Сенсор давления
Таковым послужит барометрический датчик с интерфейсом I2C BMP180. Он станет контролировать абсолютное значение параметра вокруг себя. Падение обычно сигнализирует о приближении грозы и наступлении дождя (поскольку им сопутствует область низкого давления), а увеличение, наоборот, говорит о прохождении области низкого давления и наступлении ясной сухой погоды.
Давление всегда зависит от высоты над уровнем моря и погодных условий в зоне измерения. Но в нашем случае измеряется относительное — как если бы метеостанция находилась на уровне моря.
Кроме того, монитор погоды должен быть защищен и от нагрева — воздействие источников тепла исказит показания температуры. Попадание воды также внесет помехи, в конструкции это нужно учесть и предусмотреть защиту.
Еще один важный момент — светочувствительность. Благодаря силикону в конструктиве BMP180 он способен улавливать попадающий через отверстие в корпусе микрочипа свет и нагреваться. Максимально точные измерения потребуют изоляции от окружающего света.
BMP180 соединяется через шину I2C по следующей схеме:
A4 — SDA;
A5 — SCL;
3.3V — VCC;
GND — GND.
Сборка
Процесс сборки начинается с монтажа однорядных разъемов для DHT22 и Arduino:
От вывода DATA к GND припаян резистор на 10 кОм.
Далее монтируется разъем для BMP180 (питаться датчик будет от линии 3.3 В). Компоненты соединяются шиной I2C.
На последнем этапе та же шина соединяется с дисплеем.
Так выглядит домашняя метеостанция в сборе:
Пример вывода информации об атмосферном давлении:
Программный код
Для работы понадобятся скетч Ардуино и библиотеки датчиков. Все они доступны в приложениях к статье.
Текст скетча можно скачать здесь: https://cloud.mail.ru/public/piwT/gew8pPv7M
Как сделать метеостанцию на LM35
В следующем скетче для определения температуры был использован датчик LM35, подключенный к аналоговому порту. Для точности измерений температуры необходимо будет откалибровать датчик. В этом примере измеряется только температура, при этом данные отправляются на смартфон только в том случае, если произошло изменение температуры или нажата кнопка «Обновить» в приложении.
Скетч для метеостанции на Ардуино с LM35
#include <SoftwareSerial.h> // подключение библиотеки SoftwareSerial.h SoftwareSerial mySerial(2, 3); // указываем пины rx и tx соответственно int temp1; // освобождаем память для переменной "temp1" int temp2; // освобождаем память для переменной "temp2" int temp3; // освобождаем память для переменной "temp3" float temp; // освобождаем память для переменной "temp" byte val; // освобождаем память для переменной "val" String stringT = String("*"); void setup() { pinMode(A0, INPUT); // сенсор LM35 подключим к аналоговому входу A0 Serial.begin(9600); // запуск аппаратного последовательного порта mySerial.begin(9600); // запуск программного последовательного порта } void loop() { temp1 = analogRead(A0); // считываем значение с датчика delay(60000); temp2 = analogRead(A0); // повторно считываем значение с датчика temp3 = temp1 - temp2; // определяем, изменилась ли температура // отправляем сообщение только, когда изменилась температура if (temp3 != 0) { temp = ( temp2/1023.0 )*5.0*1000/10; // вычисляем значение температуры mySerial.println(temp + stringT); // отправляем температуру на телефон Serial.println(temp + stringT); // отправляем температуру на монитор Serial.println(""); } // отправляем сообщение, когда нажата кнопка "обновить" в приложении if (Serial.available()) // проверяем, поступают ли какие-то команды { val = Serial.read(); // переменная val равна полученной команде if (val == '1') { temp = ( temp2/1023.0 )*5.0*1000/10; // вычисляем значение температуры mySerial.println(temp + stringT); // отправляем температуру на телефон Serial.println(temp + stringT); // отправляем температуру на монитор Serial.println(""); } } }
Android
Теперь напишем простое приложение для Андроид, которое запрашивает, получает, декодирует JSON-данные и отображает информацию на экране.
Наше Android-приложение будет простым насколько это возможно, только сама суть технологии. Далее вокруг этого «скелета» уже можно будет наворачивать различные «красивости».
Вот скриншот того, что должно получиться в итоге
Как видим UI просто спартанский, основан на LinearLayout, ничего лишнего.
В верхней части TextView показывает ID датчиков и их метео-данные. Кнопка «Обновить» инициирует повторный запрос к веб-серверу. Далее в EditText расположена единственная настройка программы — это URL запроса в виде
Что необходимо отметить?
В манифест добавьте строки разрешающие интернет и проверку состояния сетевого соединения :
Работа с сетью и получение данных с веб-сайта происходит следующим образом.
Используем AsyncTask, чтобы создать фоновую задачу отдельно от главного потока пользовательского интерфейса. Эта фоновая задача берет URL запроса и использует его для создания .
После того, как соединение установлено, AsyncTask загружает содержимое веб-страницы (JSON) как InputStream. Далее InputStream преобразуется в строку, которая декодируется с помощью JSONObject и отображается в пользовательском интерфейсе методом .
В MainActivity.java измените URL на ваш :
он будет использоваться по умолчанию при первом запуске Android приложения.
PHP и веб-сервер
Все настройки веб-интерфейса хранятся в . Измените его в соответствии с вашими настройками базы данных.
Задайте свой часовой пояс в формате PHP
Все доступные часовые пояса описаны здесь.
Задайте свой секретный ключ для доступа (в виде числа) который должен совпадать с константой из скетча
В нашем веб-сервере нет авторизации, входа по паролю, это усложнило бы всю конструкцию. Для прототипа это не нужно. Поэтому вся защита построена на файле , отсутствии и на этом секретном ключе для доступа.
Основной PHP скрипт принимает простой HTTP GET запрос с данными и сохраняет их в соответствующие таблицы базы данных. Если ключ не совпадает, то запрос будет отвергнут.
Скрипт используется для просмотра таблиц данных и содержит гиперссылки на остальные скрипты веб-интерфейса. Вызывайте его так
Например
выводит простые таблички, где надо помнить, что :
- датчик с id 11 это домашний датчик на сервере,
- датчик с id 20 это заоконный датчик.
Скрипт содержит функции, общие для всех PHP скриптов.
Скрипт отвечает за рисование графиков при помощи Google Charts. Вот, например, график питающего напряжения заоконного датчика. Напряжение повышается в солнечный день за счёт солнечной же батареи и затем блок питания на аккумуляторах постепенно разряжается.
экспортирует данные из таблиц базы данных MySQL в файл формата CSV. Для дальнейшего импорта и анализа в электронных таблицах.
экспортирует данные о напряжении питания заоконного датчика из базы данных MySQL в файл формата CSV. Полезно для отладки.
очищает все таблицы, т.е. удаляет все наши данные. Полезно для отладки. На этот скрипт нет ссылок из , поэтому вызывать его надо по прямой ссылке в адресной строке браузера с указанием .
При приёме данных повсеместно используется функция для предотвращения попадания в БД некорректных значений.
В корень вашего сайта не забудьте положить для предотвращения попадания в поисковые системы.
ESP8266, WiFi и передача данных
И вот теперь возвращаемся к скетчу , к той его части, которая соединяется с точкой доступа WiFi и отсылает данные на веб-сервер.
Как я уже писал, мне не удалось найти нормальную библиотеку для Arduino для управления модулем ESP8266 с помощью AT команд, пришлось «колхозить» самому. Напомню так же, что вам придется прошить в ESP8266-01 прошивку определённой версии. И теперь когда всё готово, разберём как это работает.
Для доступа к веб серверу в скетче необходимо изменить вот эти константы
В в функции сначала производится переключение ESP8266 в режим Station, т.е. он начинает работать как WiFi клиент
и далее следует подключение к точке доступа
Если подключения не происходит, то попытка повторяется (однократно)
Затем выбирается режим одиночного подключения TCP/IP
При отсылке данных от датчиков типа DHT на вебсервер используется функция с указанием типа данных как
При отсылке данных от датчиков типа BMP на вебсервер используется та же функция с указанием типа данных как
На вход функция принимает строку HTTP GET запроса и отправляет её по назначению на веб-сервер.
Внутри себя проверяет доступность ESP модуля, посылая ему команду «AT», далее проверяется подключение к WiFi и производится переподключение, если необходимо. Затем отправляются данные и соединение TCP закрывается.
Android приложение
В наше время, когда уже каждый может мигать светодиодом, никакой метеостанцией никого не удивишь. Но если поделка умеет связываться с сервером через WiFi, имеет веб-морду и мобильное приложение, то это уже кое-что! Под сервером здесь имеется в виду конечно же сервер приложений, т.е. в нашем случае это PHP-обвязка и СУБД MySQL. Не достаёт вишенки на торте, а именно приложения под Android написанием которого мы сейчас и займёмся.
Что это такое?
Наша метеостанция будет состоять из двух устройств: компактного автономного
устройства, измеряющего погодные показатели, и устройства-ретранслятора,
получающего эти показатели и отправляющего их на «народный мониторинг».
Устройства будут связываться по беспроводному каналу связи на частоте 433 МГц.
Автономная часть будет питаться от трёх пальчиковых батареек и сможет
просуществовать на одном комплекте батарей до года при периоде опроса датчиков
в 20 мин.
Такая конструкция позволяет не сверлить стены для прокладки проводов с улицы, где необходимо производить измерения, в помещение, где результатами этих
измерений надо пользоваться.
Скетч
- p160_meteostation.ino
-
#include <math.h> int minute = 1; // Параметр конкретного типа термистора (из datasheet): #define TERMIST_B 4300 #define VIN 5.0 void setup() { // мы хотим передавать информацию на компьютер через USB, а // точнее через последовательный (англ. serial) порт. // Для этого необходимо начать (англ. begin) передачу, указав // скорость. 9600 бит в секунду — традиционная скорость. // Функция «begin» не является глобальной, она принадлежит // объекту с именем «Serial». Объекты — это «продвинутые» // переменные, которые обладают собственными функциями, // к которым обращаются через символ точки. Serial.begin(9600); // передаём заголовок нашей таблицы в текстовом виде, иначе // говоря печатаем строку (англ. print line). Символы «\t» — // это специальная последовательность, которая заменяется на // знак табуляции (англ. tab): 8-кратный выровненный пробел Serial.println("Minute\tTemperature"); } void loop() { // вычисляем температуру в °С с помощью магической формулы. // Используем при этом не целые числа, а вещественные. Их ещё // называют числами с плавающей (англ. float) точкой. В // выражениях с вещественными числами обязательно нужно явно // указывать дробную часть у всех констант. Иначе дробная // часть результата будет отброшена float voltage = analogRead(A0) * VIN 1024.0; float r1 = voltage (VIN - voltage); float temperature = 1.( 1.(TERMIST_B)*log(r1)+1.(25. + 273.) ) - 273; // печатаем текущую минуту и температуру, разделяя их табом. // println переводит курсор на новую строку, а print — нет Serial.print(minute); Serial.print("\t"); Serial.println(temperature); delay(60000); // засыпаем на минуту ++minute; // увеличиваем значение минуты на 1 // откройте окно Serial Monitor в среде Arduino, оставьте на // сутки, скопируйте данные в Excel, чтобы построить графики }
Что понадобится
— микроконтроллер Arduino Uno
— термистор (терморезистор)
— сопротивление на 10 кОм
— семисегментный индикатор
— макетная плата
— соединительные провода «папа-папа»
Основой метеостанции станет термистор — элемент, сопротивление которого меняется в зависимости от температуры. Сначала я выведу информацию с сенсора на экран ноутбука, а когда разберусь со всеми этими вольтами, омами и градусами — добавлю ЖК-экран, чтобы станция работала и без компьютера.
Мы будем собирать устройство на макетной плате. Схему можно поправить за считанные мгновения и не придётся ничего перепаивать.
Общий принцип работы
Измеряющая данные окружающей среды метеостанция на Ардуино состоит из нескольких основных компонентов:
- собственно плата управления Arduino (например, Uno). На нее поступает информация со внешних датчиков, контроллер выполняет вычисления и выводит информацию на экран;
- электронный дисплей — служит для отображения поступивших с контроллера данных в понятной человекочитаемой форме;
- сенсор влажности температуры. В подобных схемах популярны датчики DHT11 и DHT22. Они регистрируют данные среды и отдают их контроллеру;
- макетная плата — основа для сборки всех компонентов. На ней фиксируются все элементы метеостанции, по ней же прокладываются электрические соединения;
- соединительные провода — с «оголенными» концами под пайку или оснащенные штекерами.
Кроме того, в плату понадобится залить соответствующее программное обеспечение — скетч. Его содержимое зависит от набора элементов и выполняемых задач, примеры скетчей мы также рассмотрим ниже.
HTTP GET и JSON
Вопрос, который нужно решить в первую очередь — это каким образом будет происходить передача данных от веб-сервера к Андроид-приложению.
Придумывать тут ничего не нужно, всё уже придумано за нас — это HTTP GET и JSON.
В нашем случае простой GET запрос к веб-серверу можно составить и отладить вручную, пока Андроид приложение ещё не готово.
В Java и в Android есть готовые библиотеки для обработки данных в формате JSON. JSON текстовый формат, читается человеком, что полезно для отладки.
Для того, чтобы сформировать текущие данные от датчиков метеостанции создадим на веб-сервере новый PHP скрипт last-data-to-json.php.
Вызов скрипта :
где , как мы помним, это секретный ключ доступа к БД.
Пример ответа в формате JSON :
Необходимо напомнить, что у нас 3 датчика. Их ID и тип (DHT или BMP) жёстко закодированы по всему коду метеостанции. Такой способ хардкордного кодирования идеологически неверен, но для наколенного прототипа (где необходимо быстрое и простое решение) это разумный компромисс.
Скрипт берет из БД самые последние данные от этих разнотипных датчиков и упаковывает в формат JSON. Выборка данных из БД «с конца» просходит таким способом :