Совершенствуя свой комнатный термостат, о котором писал раньше, я задался целью дополнить его беспроводным датчиком температуры для измерения температуры воздуха на улице, собрать термостат с питанием от батареек и заменить модули приемник-передатчик RF 433MHz другой парой радиомодулей с большей дальностью связи при напряжении питания не более 3В. По ходу решения этих задач вырисовалась автономная метеостанция, речь о которой пойдет ниже.
Тем, кто тут впервые, советую сразу перейти сюда. Тут — новая версия метеостанции.

Метеостанция состоит из двух узлов, назовем их для простоты анализатором и термометром. Связь между узлами — беспроводная, по радиоэфиру.
Анализатор построен на контроллере ATMEGA328P, измеряет температуру и влажность в помещении (датчик температуры и влажности DHT22) и напряжение питания анализатора, которое обеспечивают две батарейки АА 1,5В. На контроллер поступает сигнал с приемника LoRa, который по эфиру принимает информацию с термометра (выносного датчика). Информация с контроллера выводится на ЖК-дисплей NOKIA 5110.
В термометре, собранном тоже на контроллере ATMEGA328P, измеряется температура воздуха на улице (датчик температуры DS18B20) и напряжение питания выносного узла, организованного на двух батарейках АА 1,5 В. Передатчик LoRa этого узла передает температуру и напряжение питания на анализатор.
Контроллер ATMEGA328P и передатчик LoRa термометра для экономного расходования заряда батареек после измерений и отправки информации переводятся в режим сна. Напряжение питания на датчик DS18B20 программно подается только на время измерения температуры. Измерения и отправка данных с термометра выполняется с периодом около одной минуты.
В таком же режиме работа-сон работает и анализатор. Продолжительность работы контроллера и приемника анализатора на несколько секунд больше одной минуты. Это сделано для уверенного приема сигнала с термометра — ведь работа термометра и анализатора не синхронизированы. Затем ATMEGA328P и приемник LoRa переводятся на 14 мин в режим сна до пробуждения и старта очередного цикла. Питание на DHT22 подается только во время измерений.
Для программирования режима сна контроллеров ATMEGA328P используется библиотека LowPower.h.
С разрядом батареек на них понижается величина напряжения.

Нижний предел рабочего напряжения питания контроллера ATMEGA328P — 1,8В. При этом, заводская установка фьюз ATMEGA328P выполнена на мониторинг порога напряжения питания 2,7В, поэтому необходимо изменить заводские установки фьюз на мониторинг порога 1,8В, чтобы гарантировать рабо��у контроллера при питании от подсевших батареек.
Внутренний генератор контроллера может не запускаться на частоте 16 МГц при напряжении питания 3В или несколько ниже. У меня оба контроллера работают с кварцем 16 МГц при пониженном напряжении питания 2,7…2,8В, поэтому я не стал менять кварц 16 МГц на 8 МГц.

Для сборки устройства понадобятся компоненты, перечень которых и их ориентировочная стоимость по ценам сайта AliExpress приведены в таблице.
| Компонент | Цена, $ |
| анализатор | |
| Контроллер ATMEGA328P-PU | 1,59 |
| Датчик температуры и влажности DHT22 | 2,34 |
| Приемник-передатчик LoRa Rа-01 | 3,95 |
| ЖК-дисплей NOKIA 5110 | 1,91 |
| Макетная (монтажная) плата, монтажные провода, батарейки АА, кварцевый резонатор 16 МГц, резисторы и др. | 4,00 |
| термометр | |
| Контроллер ATMEGA328P-PU | 1,59 |
| Датчик температуры DS18B20 | 0,63 |
| Приемник-передатчик LoRa Rа-01 | 3,95 |
| Макетная плата (стеклотекстолит), монтажные провода, батарейки АА, кварцевый резонатор 16 МГц, резисторы и др. | 4,00 |
| Всего (примерно): | 24 |
Анализатор

Мозг анализатора – контроллер ATMEGA328P. Он принимает сигналы с датчика DHT22 и по протоколу SPI взаимодействует с приемником LoRa и дисплеем NOKIA 5110.
В Интернете много нареканий на низкую точность измерения влажности датчика DHT22. На сегодня есть альтернатива: более современные датчики температуры и влажности HTU21 (GY21), (Vcc = 3...5 В), Si7021,(Vcc = 1,9… 3,6 В), SHT21, (Vcc = 2.1….3,6 В).
Я использую DHT22, поскольку расхождение между показаниями влажности моего экземпляра этого датчика и серийно вып��скаемого термогигрометра LaCrosse WS-9024IT составляют не более 8-ми единиц, что вполне приемлемо для бытовых целей. Расхождение между показаниями влажности сильно увеличиваются, если величина напряжение питания DHT22 ниже 3В. Это и понятно, ведь напряжение питания DHT22 должно находиться в пределах 3…5В. Суммируя – идеально в этих условиях в схему анализатора вписывается датчик Si7021.
На картинке ниже — цоколевка элементов метеостанции.
Фьюзы и многое другое различных контроллеров, в том числе ATMEGA328P, можно читать и редактировать утилитой SinaProg. Если вы впервые сталкиваетесь с этой программой, то несмотря на интуитивно понятный интерфейс, не пытайтесь после инсталляции приложения начинать с ним работать. Сначала почитайте эту статью, в которой HWman приводит необходимые дополнения SinaProg при использовании платы Arduino UNO как загрузчика.
Советую вначале прочитать заводские установки фьюз ATMEGA328P и сохранить их значения, чтобы вернуться к ним в случае неудачи. В моих контроллерах заводские установки фьюз бит такие: LOW: 0xFF, HIGH: 0xDE, EXTENDED: 0x05 (Vcc=2.7V, BODLEVEL=101). Новые фьюзы для мониторинга порога 1,8В, которые требуется установить: LOW: 0xFF, HIGH: 0xDE, EXTENDED: 0x06 (Vcc=1.8V, BODLEVEL=110).
Скетч анализатора для загрузки в ATMEGA328P находится под спойлером.
/*
Автономная метеостанция на контроллере ATMEGA328P и питанием от батареек с беспроводным выносным датчиком, анализатор
https://habr.com/ru/post/470381/
*/
#include <SPI.h>
#include <LoRa.h>
#include <DHT.h>
#define DHTPIN 3 // what digital pin we're connected to
#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321
DHT dht(DHTPIN, DHTTYPE);
float Tin = 0;
int Hin = 0;
float BatteryInLevel; // напряжение батареи базы
String LoRaData, Tout_str, BatteryInLevel_str, BatteryOutLevel_str;
//sleep
#include <LowPower.h>
#define PowerDHT (4) //пин питания DHT22
unsigned int sleepCounter;
//Nokia 5110
#include <SPI.h>
#include <Adafruit_GFX.h> //https://esp8266.ru/forum/threads/esp8266-5110-nokia-lcd.1143/#post-16942
#include <Adafruit_PCD8544.h> //https://esp8266.ru/forum/threads/esp8266-5110-nokia-lcd.1143/#post-16942
//timer
#include <SimpleTimer.h>
SimpleTimer timer;
Adafruit_PCD8544 display = Adafruit_PCD8544(5, 7, 6);
void sendSensor() {
digitalWrite(PowerDHT, 1);
delay (2000);
Hin = dht.readHumidity();
Tin = dht.readTemperature();
/* if (isnan(Hin) || isnan(Tin)) {
// Serial.println(«Failed to read from DHT sensor!»);
return;
}*/
digitalWrite(PowerDHT, 0);
// измерение напряжения батареи:
analogReference(INTERNAL);
int sensorValue = analogRead(A4);
BatteryInLevel = (sensorValue * 3.2 / 1024);
}
void draw() {
display.clearDisplay();
//Tin
{
display.setTextSize(2);
display.setCursor(8, 0);
display.println (Tin, 1); // один знак после запятой
display.setCursor(68, 0);
display.println(«C»);
}
//Hin
{
display.setTextSize(2);
display.setCursor(8, 16);
display.println(String(Hin) + "%");
}
//Tout
{
char chr_Tout [12];
Tout_str.toCharArray(chr_Tout, 5);
display.setTextSize(1);
display.setCursor(50, 16);
display.println(String(chr_Tout) + «C»);
}
// Battery Out Level
{
char chr_BatteryOutLevel [12];
BatteryOutLevel_str.toCharArray(chr_BatteryOutLevel, 4);
display.setTextSize(1);
display.setCursor(2, 32);
display.println(«BAT Out: » + String(chr_BatteryOutLevel) + «V»);
}
// Battery In Level
{
display.setTextSize(1);
display.setCursor(2, 40);
display.println(«BAT In: „);
display.setCursor(56, 40);
display.println(BatteryInLevel, 1); //один знак после запятой
display.setCursor(74, 40);
display.println(“V»);
}
display.display();
/*
Serial.println(«Tin: » + String(Tin) + "*C");
Serial.println(«Hin: » + String(Hin) + "%");
Serial.println(«Tout: » + String(Tout_str) + "*C");
Serial.println(«BAT_In: » + String(BatteryInLevel) + «V»);
Serial.println(«BAT_Out: » + String(BatteryOutLevel_str) + «V»);
Serial.println("......");
*/
}
void sleepDevice() {
// sleepCounter = 65 — 10 min
// sleepCounter = 91 — 14 min
for (sleepCounter = 91; sleepCounter > 0; sleepCounter--) //91!!!
{
LoRa.sleep ();
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
}
LoRa.sleep ();
}
void SignalReception () {
// try to parse packet
int packetSize = LoRa.parsePacket();
if (packetSize) {
// read packet
while (LoRa.available()) {
LoRaData = LoRa.readString();
// Serial.println(«Принято: » + (LoRaData));
}
int pos1 = LoRaData.indexOf('#');
Tout_str = LoRaData.substring(0, pos1);
BatteryOutLevel_str = LoRaData.substring(pos1 + 1, LoRaData.length());
}
}
void setup() {
//Serial.begin(9600);
pinMode(PowerDHT, OUTPUT);
// инициализация и очистка дисплея
display.begin();
display.clearDisplay();
display.display();
display.setContrast(60); // установка контраста
display.clearDisplay();
display.setTextSize(2);
display.setCursor(12, 16);
display.println (" >>>>> "); //индикация начала работы при включении
display.display();
dht.begin();
sendSensor();
draw();
while (!LoRa.begin(433E6)) {
//Serial.println(".");
delay(500);
}
// Диапазон для синхрослова – между «0 — 0xFF».
LoRa.setSyncWord(0xF3);
//Serial.println(«LoRa Initializing»);
timer.setInterval(20000, sendSensor);
timer.setInterval(5000, draw);
timer.setInterval(65000, sleepDevice);
}
void loop() {
SignalReception();
timer.run();
}
```
Для работы с контроллерами ATMEGA328P в качестве программатора я использую плату Arduino UNO. На Youtube есть хорошее видео по установке загрузчика и загрузки скетчей в контроллер ATMEGA328 с помощью платы Arduino UNO.
В скетче закомментированы команды вывода в монитор последовательного порта (Serial). В случае необходимости — раскомментируйте команды.
Цикл начинается с прослушивания эфира и приема информации приемником LoRa. Таймером установлено время прослушивания — 65 сек. В это время с периодом 5 сек обновляется информация на дисплее NOKIA и с периодом 20 сек (3 раза) датчиком DHT22 проводятся измерения температуры, влажности, а также уровень напряжения батареек через один из аналоговых входов контроллера. Напряжение питания на DHT22 подается только во время измерений с минимальной задержкой 2 сек, при которой датчик еще работает. Выход АЦП в скетче масштабирован на напряжение новых батареек, которое составляет 3,2В (1,6В х 2). Время прослушивания эфира выбрано несколько больше 1 мин для уверенного приема одной пачки с термометра, который работает на передачу с периодом 1 мин, но об этом ниже. Затем на 62-ой секунде контроллер и приемник переводятся в режим сна, который длится примерно 14 мин, т.е. период цикла «работа — сон» анализатора — около 15 мин. Замечу, что режим сна в анализаторе – это вынуждения мера, призванная существенно уменьшить потребление.
В таблице ниже для сравнения приведены характеристики термогигрометра LaCrosse WS-9024IT и анализатора с этого проекта.
| Параметр | LaCrosse WS-9024IT | Сadil_TM |
| Питание | 2хАА, 3В, Durasell | 2хАА, 3В, GP Ultra+, 1800 мА*ч |
| Потребление сна | 350 мкА (10 мкА) | |
| Продолжительность сна | 14 мин | |
| Операционное потребление | < 200 мкА | 12-18 мА |
| Продолжительность работы | около 1 мин | |
| Период цикла работа/сон | около 5 сек | 15 мин |
Ток потребления LaCrosse очень сильно «пляшет». В таблице я привел пиковое измеренное значение, чтобы показать порядок потребления: не более двух сотен микроампер.

Хотел дополнить таблицу результатами аналогичных любительских разработок, но ничего не нашел. Наверное потому, что большинство любителей выводят инфу с датчиков на компьютер, планшет, смартфон или транзитом на один из сервисов в сети, где проблемы экономии ресурса батареек просто не существует.
Основной вклад в потребление сна анализатора (350 мкА) вносит ЖК-дисплей. Если его отключить, то потребление упадет до 10 мкА. Пиковое потребление 18 мА приходится на время приема приемником LoRa сигнала с передатчика, но прием сигнала длится несколько микросекунд. Это время очень мало по сравнению с минутой работы приемника в режиме прослушивания и потреблением 10 мА, поэтому я не стал учитывать этот кратковременный пик при расчете времени работы на одном комплекте батареек.
Термометр

Емкость и напряжение батареек на морозе быстро падают. Поэтому, чтобы не подвергать батарейки да и устройство в целом столь сильным испытаниям я вынес за пределы помещения только датчик температуры DS18B20, а сам узел и батарейки находятся в помещении. DS18B20 соединяется с платой узла тонким трехжильным проводом. Это решение я подсмотрел в своей серийной метеостанции – разработчики уверены, что в квартире всегда найдется щель для укладки провода диаметром в несколько миллиметров.

Фьюзы для ATMEGA328P термометра такие же, как и для анализатора.
Узел термометра тоже построен на контроллере ATMEGA328P. Он принимает сигнал с датчика DS18B20, измеряет напряжение питания и управляет передатчиком LoRa.
Скетч термометра – под спойлером.
/*
Автономная метеостанция на контроллере ATMEGA328P и питанием от батареек с беспроводным выносным датчиком, термометр
https://habr.com/ru/post/470381/
*/
#include <OneWire.h>
OneWire ds(7); //pin 13, Atmega328P
#include <SPI.h>
#include <LoRa.h>
#include <LowPower.h>
#define PowerDS18B20 (6) //pin 12 (Atmega328P), питаниe DS18B20
unsigned int sleepCounter; // счетчик, задающий время сна
float Tout; //температура
int i; // отсчет числа циклов при включении устройства интенсивного режима (20 циклов за 1 мин)
String messageTout; // LoRa-сообщение
float batteryLevel; // напряжение батареи
const int batteryPin = A0; // pin 23 (Atmega328P), к которому подключена батарея для измерения напряжения
void Measurement () {
//измерение температуры
byte data[2];
digitalWrite(PowerDS18B20, 1);
ds.reset();
ds.write(0xCC); // пропуск поиска по адресу (1 датчик)
ds.write(0x44); // команда на измерение
delay(700);
ds.reset();
ds.write(0xCC);
ds.write(0xBE); // передача регистров со значением температуры
data[0] = ds.read();
data[1] = ds.read();
Tout = ((data[1] << 8) | data[0]) * 0.0625;
// Serial.println(«Tout= „+ String(Tout));
digitalWrite(PowerDS18B20, 0);
// измерение напряжения батареи:
analogReference(INTERNAL);
int sensorValue = analogRead(A0);
batteryLevel = (sensorValue * 3.2 / 1024);
// Serial.println(“BAT= „+ String(batteryLevel));
}
void SetSynchLoRa () {
int counter = 0;
while (!LoRa.begin(433E6) && counter < 10) {
// Serial.print(“.»);
counter++;
delay(500);
}
LoRa.setTxPower(4); //мощность передатчика 2-20 дБ
/* if (counter == 10) {
// Serial.println(«Failed to initialize ...»);
}*/
LoRa.setSyncWord(0xF3);
}
void SendMessage () {
// отправка данных (температура, напряжение батареи)
messageTout = String(Tout) + "#" + String(batteryLevel);
// Serial.println(messageTout);
delay(250);
LoRa.beginPacket();
LoRa.print(messageTout);
LoRa.endPacket();
}
void setup() {
//Serial.begin(9600);
// Serial.println(«Initializing ...»);
pinMode(PowerDS18B20, OUTPUT);
SetSynchLoRa ();
}
void loop() {
//Serial.println("");
//Serial.println(«i = » + String(i));
if (i >= 30) { // i >= 30 (1 мин) — обычный режим (измерение, о��правка — 1 раз/1 мин)
for (sleepCounter = 5; sleepCounter > 0; sleepCounter--)
{
LoRa.sleep ();
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
}
Measurement ();
SendMessage ();
LoRa.sleep ();
} else
{ //интенсивный режим продолжительностью 1 мин, отправка — 1 раз/2 сек
Measurement ();
SendMessage ();
delay (1000);
}
i++;
if (i >= 30) i = 30; //уменьшение разрядности заполнения счетчика
}
```
Пара передатчик-приемник LoRa обеспечивает устойчивую связь на расстоянии 1,5 км при прямой видимости и до 300м в условиях городской застройки, естественно, на максимальной или близкой к максимальной мощности передатчика: 17-20 дБ. Для устойчивой связи в пределах квартиры оказалось достаточно 4 дБ.
Вначале при подключении питания термометр на протяжении одной минуты работает в интенсивном режиме. Он измеряет температуру, напряжение батареек и посылает их значения в эфир через каждые 2 сек. Это сделано для удобства. Допустим, при замене батареек или отладке не придется ждать минуту. Информация с датчика появится на дисплее анализатора в первые секунды после подключения батареек термометра и анализатора. Естественно, стоит поторопиться и не делать разрыва во времени больше минуты между подключением батареек на обоих узлах.
Затем выносной датчик переходит в штатный режим. После измерений и отправки информации, которые длятся несколько больше 1-ой секунды, контроллер и передатчик программно переводятся в режим сна длительностью около 1-ой минуты.
И сравнительная таблица. В ней есть результаты пары похожих проектов из Интернета.
| Параметр | LaCrosse WS-9024IT | maniacbug | avs24rus | Сadil_TM |
| Питание | 2хААА, 3В, Durasell | 3В, CR2450 Renata, 540 мА*ч | 3В, CR2450, 550-610 мА*ч | 2хАА, 3В, GP Ultra+, 1800 мА*ч |
| Потребление сна | 0,14 мА (?) | 14 мкА | 5 мкА | |
| Продолжительность сна | 1 мин | |||
| Операционное потребление | < 700 мкА | 13,57 мА | 16 — 18 мА | 14 мА |
| Продолжительность работы | 0,027 сек | 1 сек | ||
| Период цикла работа/сон | около 5 сек | 1 мин | 10 мин | 1 мин |
Если узлы собраны без ошибок, то на дисплее увидим такую картинку:

Из сравнительных таблиц видно, что пиковое потребление любительских устройств на порядок выше, чем в аналогичной за функциями промышленной LaCrosse. Например, 14 мА против 700 мкА для выносного датчика и 10...18 мА против 200 мкА для анализатора. Такое разительное отличие в максимальном потреблении объясняется, на мой взгляд, тем, что контроллеры в любительских схемах запрограммированы с использованием платформы Arduino IDE, тяжеловесных функций и библиотек, а в промышленных продуктах — скорее всего на одном из языков низкого уровня или, например, на С++ (кстати, базовом языке Arduino) или C(Си). Если же использовать эти языки, то, уверен, можно выйти на потребление, сравнимое с промышленными образцами. Впрочем, это очень убедительно экспериментально показал HWman в своей публикации «Почему многие не любят Arduino». Выполнение простейшего скетча до десятка строк (Blink), выполненного в Arduino IDE в одном случае и в другом — «простом Си», как говорит автор в видео, приводит к проигрышу в производительности в 26 раз. Короче, повышенное потребление ресурсов – это плата за комфорт и небольшие усилия со стороны программиста – остальное за него в Arduino сделают «прожорливые» функции среды разработки. Предчувствую — придется напрячься и освоить хотя бы азы С/С++, функции которого компилируются Arduino IDE.
Выводы
• Собранные анализатор и термометр имеют слишком большое потребление тока по сравнению с промышленными образцами.
• К двум батарейкам питания в схемах напрашивается третья, тогда автоматически решаются следующие проблемы: отпадает необходимость в переустановке фьюз, устойчивая работа контроллера на частоте 16 МГц, работа датчиков DHT22, DS18B20 вдали от нижнего порога их напряжения питания. Последнее немаловажно, поскольку напряжение питания подается на датчики не прямо, а программно через ключ с пина контроллера, на котором падает порядка 1В.
• Применение радиомодулей LoRa, с программно заданной мощностью передатчика 4 дБ, позволило установить устойчивую связь в пределах квартиры с питанием модулей от двух батареек АА.
Ссылки по теме
Снова о автономной Arduino-метеостанции на батарейках
Узел беспроводного датчика с низким энергопотреблением
Беспроводный Lighting-Sensor с питанием от CR2450
Беспроводной датчик температуры, влажности и атмосферного давления на nRF52832
Термометр с беспроводной передачей данных
Превращаем Arduino в полноценный AVRISP программатор
LoRa и сон
Узнайте о битах конфигурации ATmega328P и о том, как использовать их с внешним кварцевым резонатором
Калькулятор фьюзов AVR
Почему многие не любят Arduino
Грандиозное тестирование батареек
Батарейки на морозе



