Автономная метеостанция на контроллере ATMEGA328P и питанием от батареек с беспроводным выносным датчиком

Совершенствуя свой комнатный термостат, о котором писал раньше, я задался целью дополнить его беспроводным датчиком температуры для измерения температуры воздуха на улице, собрать термостат с питанием от батареек и заменить модули приемник-передатчик 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 находится под спойлером.

«`cpp
/*
Автономная метеостанция на контроллере 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;
>*/

// измерение напряжения батареи:
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();

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);
>

Для работы с контроллерами 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.

Скетч термометра – под спойлером.

«`cpp
/*
Автономная метеостанция на контроллере ATMEGA328P и питанием от батареек с беспроводным выносным датчиком, термометр
https://habr.com/ru/post/470381/
*/

#include OneWire.h>
OneWire ds(7); //pin 13, Atmega328P

#include SPI.h>
#include LoRa.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];

ds.reset();
ds.write(0xCC); // пропуск поиска по адресу (1 датчик)
ds.write(0x44); // команда на измерение

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 дБ, позволило установить устойчивую связь в пределах квартиры с питанием модулей от двух батареек АА.


Источник: habr.com