Помогите с выбором (исходя из ТЗ)

Мужик из полиуретана
Offline
Зарегистрирован: 12.09.2015

Здравствуйте!
В мои служебные обязанности входит внесение в обычный бумажный журнал температуры (в одном и том же помещении, на 3 уровнях) и влажности, два раза в день.
Есть сильное желание применить на практике ардуинку и С++, который сейчас активно изучаю, ну и слегка облегчить себе жизнь.
Подскажите, какую ардуино и какие датчики целесообразней будет приобрести, исходя из условий:

1. Сбор температуры с 3 датчиков и 1 датчика влажности (можно и влажность с трех датчиков, не критично), два раза в сутки - утром и вечером.
2. Запись этих данных(дата, время, температура1,температура2,температура3,влажность) в какую-либо память, так же, два раза в сутки.
3.Периодически, раз в месяц - экспорт этих данных.
4. Нужны либо беспроводные автономные датчики(саму ардуино запитаю от БП), либо же проводные датчики и общее аккумуляторное питание.
5.В случае аккумуляторного питания - достаточно чтобы все включалось только два раза в сутки, для записи данных, в целях экономии заряда.
6.дисплей, на котором отображалась бы вся информация, был бы весьма кстати, если он недорого стоит. В целях экономии заряда, опять, включение дисплея и всего остального можно сделать только по кнопке.

В какой бюджет реально уложиться? Не включая БП.

Первое время планирую всячески поиграться с ардуино, а потом уже использовать постоянно в качестве термометра-гигрометра-журнала.

Мужик из полиуретана
Offline
Зарегистрирован: 12.09.2015

P.S. Да, так же интересны бюджетные аналоги ардуины.

vvadim
Offline
Зарегистрирован: 23.05.2012

самый дешёвый вариант закупка компонентов на ebay.
ардуина подойдёт любая, я предпочитаю Nano.
датчик dht 22  - температура и влажность
датчик DS18b20 - температура
модуль SD Card
дисплей lcd 1602
часы DS3231

посмотрите стоимость на эбей
в магазинах будет в 2 - 3 раза дороже

ну и лазим по сети с поиском примеров и учимся программировать мк.

 

 

Гриша
Offline
Зарегистрирован: 27.04.2014

Мужик из полиуретана пишет:
Здравствуйте! В мои служебные обязанности входит внесение в обычный бумажный журнал температуры (в одном и том же помещении, на 3 уровнях) и влажности, два раза в день.

возможно лучше не CD карта, а Ethernet shield и с компа снимать показания, кинуть витую и организовать PoE. Бывает, железяка сбои дает, можно влететь если данные критичны. Но с Ethernet shield сам не баловался и утверждать не могу.

Andrey12
Andrey12 аватар
Offline
Зарегистрирован: 26.12.2014

vvadim пишет:

дисплей lcd 1602

 

лучше lcd 2004 и с I2C

но если брать у киатйцев русского там не будет, только латиница и "китайница"

Мужик из полиуретана
Offline
Зарегистрирован: 12.09.2015

vvadim пишет:

самый дешёвый вариант закупка компонентов на ebay.
ардуина подойдёт любая, я предпочитаю Nano.
датчик dht 22  - температура и влажность
датчик DS18b20 - температура
модуль SD Card
дисплей lcd 1602
часы DS3231

посмотрите стоимость на эбей
в магазинах будет в 2 - 3 раза дороже

ну и лазим по сети с поиском примеров и учимся программировать мк.

Спасибо большое! Мне сейчас главное определиться что заказывать, чтобы не ждать еще месяц если вдруг при реализации какие-то подводные камни вылезут и понадобится еще что-то заказывать.
Т.е. на ардуино нано хватит пинов для подключения всего этого (3 dht22, 1 ds18b20, sd card, lcd 1602, ds3231) ? 

Мужик из полиуретана
Offline
Зарегистрирован: 12.09.2015

Гриша пишет:

Мужик из полиуретана пишет:
Здравствуйте! В мои служебные обязанности входит внесение в обычный бумажный журнал температуры (в одном и том же помещении, на 3 уровнях) и влажности, два раза в день.

возможно лучше не CD карта, а Ethernet shield и с компа снимать показания, кинуть витую и организовать PoE. Бывает, железяка сбои дает, можно влететь если данные критичны. Но с Ethernet shield сам не баловался и утверждать не могу.

Данные не критичны, просто статистика и отчетность для клиентов. Мой предшественник так и вовсе заполнял это из головы, т.к. обычный психрометрический гигрометр, который используется сейчас, довольно быстро засоряется и начинаеть врать в сторону завышения влажности.

Увы, витую кинуть мне точно не дадут - снимать данные желательно в центре складского помещения. Поэтому еще важный для меня момент - возможно ли ардуину уводить в стендбай и будить только два раза в сутки, или же по кнопке? И на какое время хватит тогда, допустим, 9V батарейки? В крайнем случае, можно все смонтировать не в центре, возле сети 220v и запитать через БП.

С другой стороны, там есть рабочий wi-fi, без доступа к интернету, с подключением к серверу через прокси, у которого можно расшарить какую-нибудь папку и хранить данные там, но я смутно представляю как реализовать это программно.

Мужик из полиуретана
Offline
Зарегистрирован: 12.09.2015

Andrey12 пишет:

vvadim пишет:

дисплей lcd 1602

 

лучше lcd 2004 и с I2C

но если брать у киатйцев русского там не будет, только латиница и "китайница"

Латиница и не нужна, все что будет отображаться - t 1.5m, t 6m, t 9m и v.

1602 вроде бы дешевле :)

vvadim
Offline
Зарегистрирован: 23.05.2012

Мужик из полиуретана пишет:

Спасибо большое! Мне сейчас главное определиться что заказывать, чтобы не ждать еще месяц если вдруг при реализации какие-то подводные камни вылезут и понадобится еще что-то заказывать.

Т.е. на ардуино нано хватит пинов для подключения всего этого (3 dht22, 1 ds18b20, sd card, lcd 1602, ds3231) ? 

пинов хватает, даже четыре  свободных останется.

dht22 - температура и влажность
ds18b20 - только температура

Гриша
Offline
Зарегистрирован: 27.04.2014

Мужик из полиуретана пишет:

Поэтому еще важный для меня момент - возможно ли ардуину уводить в стендбай и будить только два раза в сутки, или же по кнопке? И на какое время хватит тогда, допустим, 9V батарейки? В крайнем случае, можно все смонтировать не в центре, возле сети 220v и запитать через БП.

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

Сделайте от БП на карту, а потом WI-FI, а потом автономку. Это я к тому, что купить детальки лучше скопом. Можно вообще начать с экрана и датчиков и ходить смотреть, пока КОДите более совершенное устройство, за одно и качество датчиков (статистику) можно посмотреть.

ЗЫ трудноватая задача для первого устройства…

Мужик из полиуретана
Offline
Зарегистрирован: 12.09.2015

Гриша пишет:

Мужик из полиуретана пишет:

Поэтому еще важный для меня момент - возможно ли ардуину уводить в стендбай и будить только два раза в сутки, или же по кнопке? И на какое время хватит тогда, допустим, 9V батарейки? В крайнем случае, можно все смонтировать не в центре, возле сети 220v и запитать через БП.

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

Сделайте от БП на карту, а потом WI-FI, а потом автономку. Это я к тому, что купить детальки лучше скопом. Можно вообще начать с экрана и датчиков и ходить смотреть, пока КОДите более совершенное устройство, за одно и качество датчиков (статистику) можно посмотреть.

ЗЫ трудноватая задача для первого устройства…

Само собой, подходить буду к конечному итогу постепенно, начиная с совсем банального, как следует тестируя.

В плане электроники понимание и, какой-никакой, опыт имеются, в том числе и проектирование (правда, преимущественно в сфере аудио), но вот мк для меня темный лес, и с++ на уровне эдак первого курса, поэтому тему и создал.

Самое главное- желание есть :)

bwn
Offline
Зарегистрирован: 25.08.2014

Только зачем приумножать сущности в виде SD? Для месячного лога за глаза хватает родного EEPROM. По ресурсу на 8тыс.лет. Шансов на сбой меньше. Единственное неудобство - раз в месяц принести комп или девайс к нему. Будить можно DS-кой. ИМХО.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Тоже хотел посоветовать заменить SD на EEPROM. По прикидкам, хватит на 3 месяца (2-3 байта дата и дважды в дениь по 4 байта измерений = 10-11 байт), а дальше - по кругу.

Если требуется именно бумажный журнал, даже с компом ходить не нужно - на месте кнопками перебираешь дни и списываешь показания в журнал.

vitalikost
Offline
Зарегистрирован: 28.11.2014

Я б посмотрел бы в сторону esp 8266. Ну это если все 3 точки в пределах досягаемости Wi-fi сети. 

Мужик из полиуретана
Offline
Зарегистрирован: 12.09.2015

andriano пишет:

Тоже хотел посоветовать заменить SD на EEPROM. По прикидкам, хватит на 3 месяца (2-3 байта дата и дважды в дениь по 4 байта измерений = 10-11 байт), а дальше - по кругу.

Если требуется именно бумажный журнал, даже с компом ходить не нужно - на месте кнопками перебираешь дни и списываешь показания в журнал.

Отличный вариант. Плодить сущности в виде СД и Wi-Fi тоже не хочется, разве что исключительно ради эксперимента и опыта, но это потом, сначала бы это все реализовать.

Мужик из полиуретана
Offline
Зарегистрирован: 12.09.2015

vitalikost пишет:

Я б посмотрел бы в сторону esp 8266. Ну это если все 3 точки в пределах досягаемости Wi-fi сети. 

Все три в пределах, но все-таки тяготею к ардуине - хочется до этого с ней поиграться.

Да и на coursera планирую пройти курс по ардуине.

Мужик из полиуретана
Offline
Зарегистрирован: 12.09.2015

Начал писать скетч.

Подключил DS3231, DS18B20, два DHT22, организовал считывание со всего этого данных, включая среднюю влажность с двух датчиков, вывод всего этого на экран\ком-порт.

Теперь думаю как реализовать запись в память, пока это все выглядит довольно коряво:

if (hour() == 17 && minute() == 0 && second() == 0 )
{
   EEPROM.write(addressWrite, hour());
   addressWrite = addressWrite + 1;
    EEPROM.write(addressWrite, day());
   addressWrite = addressWrite + 1;
   EEPROM.write(addressWrite, month());
  addressWrite = addressWrite + 1;
   EEPROM.write(addressWrite, humydity);
   addressWrite = addressWrite + 1;
   EEPROM.write(addressWrite, t1);
   addressWrite = addressWrite + 1;
   EEPROM.write(addressWrite, t2);
   addressWrite = addressWrite + 1;
   EEPROM.write(addressWrite, t3);
   addressWrite = addressWrite + 1;
   
   if (addressWrite == 512)
   addressWrite = 0;
   
   delay(100);
}

7 байт на одну запись данных, две записи в день, итого памяти хватит на 36 дней , а ресурса eeprom на 19 лет - в принципе, устраивает.

Т.к. запись будет производится либо в 8 часов, либо в 17 часов, можно сэкономить один байт, просто добавляя сотню к значению числа (12 - 8 утра 12 числа, 112 - 17 вечера 12 числа), это добавит еще 6 дней.

Только тогда остается затык с записью отрицательной температуры, мне видится только такое решение - переводить температуру в значение от 0 до 254, беря за 0 градусов - 127(например, -7 градусов - 120, 18 градусов - 145)  И, следовательно, писать функцию, которая это будет делать и при записи, и при чтении из eeprom.

Чтобы не заливать каждый раз скетч на чтение данных из еепром и потом назад рабочий скетч, чтение и вывод данных планирую организовать по нажатию кнопки, в этом же скетче.

 

Тогда остается вопрос по энергосбережению.

А если в скетче инциализировать датчики и модуль времени и просто оставить delay, за исключением трех ситуаций :

1)когда нажата кнопка на чтение еепром,

2) когда 8 часов

3)когда 17 часов

и это сильно поможет в плане энергосбережения ?

и вообще, можно ли так - запускать delay без указания миллисекунд?

 

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

1.1. Т.к. Вы не пишете год, вероятно, он предполагается известным. При двух записях в сутки и известно годе запись однозначно идентифицируетися числом от 0 до 366*2-1, для чего достаотчно 10 бит.

1.2. Если записи идут подряд без пропусков, каждую запись вообще не нужно снабжать каким-либо заголовком, достаточно единственного заголовка перед первой записью и положения записи в массиве.

1.3. Для температуры в подавляющем числе случаев достаточно диапазона в 64 значения (зависит от климатической зоны, например, от -27 до + 36), в крайнем случае - за глаза 128 значений, т.е. 6-7 бит. А если речь идет об отапливаемом помещении, достаточно будет обойтись 5 разрядами (32 значения).

1.4. Т.к. температура измеряется в одном и том же помещении, разница температур вряд ли превысит +-8 градусов, следовательно, для двух других отсчетов темепературы достаточно будет указать лишь отличие от первой. Т.е. 2 раза по 4 бита.

1.6. Влажность, тоже, мне кажется, должна поместиться в диапазон 64 значения. В крайнем случае - 128. Итого, 6-7 бит. Хотя, мне кажется, погрешность влажности гораздо выше 1 %. Если, скажем, она процентов 5, то достаточно 16 значений и 4 битов.

1.7. Итого, если считать, что дату в запись не включаем, 5 разрядов на 1-ю температуру и по 4 на 2-ю и 3-ю, а также 5 разрядов на влажность, получается 18 бит на запись. Т.е. трех байтов за глаза будет достаточно.

2. 512 нацело на 7 не делится, следовательно, Ваше "заворачивание в начало" сработает не по достижении адреса 512, а лишь по достижении 512*7. Т.е. 6/7 всех записей Вы либо потеряете, либо не сможете расшифровать.

3. Ваш способ определения, когда нужно писать, не гарантирует ни того, что запись в нужное времея будет произведена, ни, тем более, того, что если она будет произведена, она будет единственной. Вероятнее всего, будет произведено 8-9 записей подряд, соответствующих одному моменту времени (в пределах одной секунды).

 

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

bwn
Offline
Зарегистрирован: 25.08.2014

При delay() вы сможете общаться с МК только по прерыванию и ничего не сэкономите. Для энергосбережения надо спать укладывать.

Мужик из полиуретана
Offline
Зарегистрирован: 12.09.2015

andriano пишет:

1.1. Т.к. Вы не пишете год, вероятно, он предполагается известным. При двух записях в сутки и известно годе запись однозначно идентифицируетися числом от 0 до 366*2-1, для чего достаотчно 10 бит.

1.2. Если записи идут подряд без пропусков, каждую запись вообще не нужно снабжать каким-либо заголовком, достаточно единственного заголовка перед первой записью и положения записи в массиве.

1.3. Для температуры в подавляющем числе случаев достаточно диапазона в 64 значения (зависит от климатической зоны, например, от -27 до + 36), в крайнем случае - за глаза 128 значений, т.е. 6-7 бит. А если речь идет об отапливаемом помещении, достаточно будет обойтись 5 разрядами (32 значения).

1.4. Т.к. температура измеряется в одном и том же помещении, разница температур вряд ли превысит +-8 градусов, следовательно, для двух других отсчетов темепературы достаточно будет указать лишь отличие от первой. Т.е. 2 раза по 4 бита.

1.6. Влажность, тоже, мне кажется, должна поместиться в диапазон 64 значения. В крайнем случае - 128. Итого, 6-7 бит. Хотя, мне кажется, погрешность влажности гораздо выше 1 %. Если, скажем, она процентов 5, то достаточно 16 значений и 4 битов.

1.7. Итого, если считать, что дату в запись не включаем, 5 разрядов на 1-ю температуру и по 4 на 2-ю и 3-ю, а также 5 разрядов на влажность, получается 18 бит на запись. Т.е. трех байтов за глаза будет достаточно.

Спасибо, это все круто, конечно, но я не представляю себе как это корректно реализовать, и в плане записи и в плане чтения %) Температура в помещении, скорее всего, не будет опускаться ниже 0-5 градусов и подниматься выше 25 в течении года, но мне интересно ставить себе задачу так, чтобы поломать голову и поучиться применять альтернативные решения, поэтому хочу реализовать, так сказать, по паспорту датчиков - температуру от -55 до 100, влажность от 0 до 100.

По EEPROM я ошибся, на моей нано целый килобайт, в принципе, даже если писать по 8 байт на одну запись(час, число, месяц, год, темп1, темп2, темп3, влажность), хватит на 64 дня - два месяца - вполне предостаточно, вытаскивать и переписывать данные собираюсь не реже одного раза в месяц. 

Но, блин, очень интересно попробовать реализовать вашу концепцию, в три байта.

andriano пишет:

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

Точно, нашел библиотеку для DS3231, с примером будильника, буду ковырять

/*
  DS3231: Real-Time Clock. Alarm simple
  Read more: www.jarzebski.pl/arduino/komponenty/zegar-czasu-rzeczywistego-rtc-DS3231...
  GIT: https://github.com/jarzebski/Arduino-DS3231
  Web: http://www.jarzebski.pl
  (c) 2014 by Korneliusz Jarzebski
*/

#include <Wire.h>
#include <DS3231.h>

DS3231 clock;
RTCDateTime dt;
boolean isAlarm = false;
boolean alarmState = false;
int alarmLED = 4;

void alarmFunction()
{
  Serial.println("*** INT 0 ***");
  isAlarm = true;
}

void setup()
{
  Serial.begin(9600);
  
  // Initialize DS3231
  Serial.println("Initialize DS3231");;
  clock.begin();
 
  // Disarm alarms and clear alarms for this example, because alarms is battery backed.
  // Under normal conditions, the settings should be reset after power and restart microcontroller.
  clock.armAlarm1(false);
  clock.armAlarm2(false);
  clock.clearAlarm1();
  clock.clearAlarm2();

  // Manual (Year, Month, Day, Hour, Minute, Second)
  clock.setDateTime(2014, 4, 25, 0, 0, 0);

  // Set Alarm1 - Every 20s in each minute
  // setAlarm1(Date or Day, Hour, Minute, Second, Mode, Armed = true)
  clock.setAlarm1(0, 0, 0, 10, DS3231_MATCH_S);

  // Attach Interrput 0. In Arduino UNO connect DS3231 INT to Arduino Pin 2
  attachInterrupt(0, alarmFunction, FALLING);

  // Setup LED Pin
  pinMode(alarmLED, OUTPUT);
}

void loop()
{
  dt = clock.getDateTime();
  Serial.println(clock.dateFormat("d-m-Y H:i:s - l", dt));

  if (isAlarm)
  {
    digitalWrite(alarmLED, alarmState);
    alarmState = !alarmState;
    clock.clearAlarm1();
  } 

  delay(1000);
}

ссылка на библиотеку - https://github.com/jarzebski/Arduino-DS3231

Вдруг кому пригодится.

Tomasina
Tomasina аватар
Offline
Зарегистрирован: 09.03.2013

andriano пишет:
 

а вот, кстати, да. Как можно ужать два значения (допустим, уличную температуру и влажность, либо часы и минуты) и записать их в одну ячейку EEPROM так, чтобы можно было обратно распаковать без потерь?

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Tomasina пишет:

а вот, кстати, да. Как можно ужать два значения (допустим, уличную температуру и влажность, либо часы и минуты) и записать их в одну ячейку EEPROM так, чтобы можно было обратно распаковать без потерь?

Вообще-то я это подробно расписал аж на 5 пунктов.

Если что-то непонятно, задавайте конкретные вопросы.

Tomasina
Tomasina аватар
Offline
Зарегистрирован: 09.03.2013

слишком кратко расписано, хотя бы часть с примерами было бы нагляднее. И по-моему, там запись в более чем одну ячейку.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Мужик из полиуретана пишет:

Спасибо, это все круто, конечно, но я не представляю себе как это корректно реализовать, и в плане записи и в плане чтения %)

Встречный вопрос: Вы с битовыми операциями знакомы?

Цитата:

Температура в помещении, скорее всего, не будет опускаться ниже 0-5 градусов и подниматься выше 25 в течении года, но мне интересно ставить себе задачу так, чтобы поломать голову и поучиться применять альтернативные решения, поэтому хочу реализовать, так сказать, по паспорту датчиков - температуру от -55 до 100, влажность от 0 до 100.

Видите ли, универсальные решения всегда существенно более ресурсоемки, чем специализированные.

Это - одна из причин, по которой предпочтение следует отдавать решениям для конкретной ситуации.

Правда, бывает и обратный эффект - при разработке что-то может быть не учтено и решение не сработает, возможно, в самый ответственный момент. Например, когда в помещении случится авария с отоплением, данные по температуре будут утеряны, т.к. она выйдет за пределы прогнозируемого диапазона.

Цитата:

По EEPROM я ошибся, на моей нано целый килобайт, в принципе, даже если писать по 8 байт на одну запись(час, число, месяц, год, темп1, темп2, темп3, влажность), хватит на 64 дня - два месяца - вполне предостаточно, вытаскивать и переписывать данные собираюсь не реже одного раза в месяц. 

Но, блин, очень интересно попробовать реализовать вашу концепцию, в три байта.

Памяти никогда не бывает много.

Я в своем проекте сразу понял, что 1К мне явно недостаточно и озаботился подключением внешних 32К по I2C. Хотел даже 64К, но не нашел по приемлемой цене.

И практика показала, что:

1. EEPROM понадобилась существенно ранье, чем проект подошел к стадии завершения и цель, для которой она сейчас уже используется (временно) не была предусмотрена заранее. Просто она оказалась очень кстати для совершенно другой задачи.

2. Естественно, в этой задаче выяснилось, что 32К - это довольно мало и я более двух десятков раз повторял измерения и сливал результат на компьютер, чтобы набрать необходимую статистику.

 

Кстати, категорически советую писать блоками равными степени двойки. В Вашем случае это почти безальтернативно 4 байта, хотя если Вы по каким-то причинам не сумеете ужать до 4 байт, я советую писать по 8, а не по 7. Для этого есть сразу несколько причин.

Кроме того, рекомендую первую запись использовать не для данных, а для заголовка. Например, первые 4 байта - начальные дата и время, последующие четверки - данные (подряд, без указания времени). Возможно, последняя четверка - финальные дата/время для проверки.

Если считывание может происходить в любой момент, рекомендую также прописывать конец записи, т.е. за один цикл записывать текущие 4 байта и "стирать" последующие 4 за ними, записывая в них 4-байтовую величину, которая никак не может встретиться в нормальных данных.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Tomasina пишет:

слишком кратко расписано, хотя бы часть с примерами было бы нагляднее. И по-моему, там запись в более чем одну ячейку.

Хорошо, подробный пример, как записать дату/время в 10 разрядов:

0 - не используется,

1 - 1 января 8 часов,

2 - 1 января 17 часов,

3 - 2 января 8 часов,

4 - 2 января 17 часов,

...

62 - 31 января 17 часов,

63 - 1 февраля 8 часов,

---

118 - 28 февраля 17 часов,

119 - 29 февраля 8 часов,

120 - 29 февраля 17 часов,

121 - 1 марта 8 часов,

...

732 - 31 декабря 17 часов.

733 - 1023 - не используются.

Это достаточно подробно или надо было точно расписать все 1024 значения?

Мужик из полиуретана
Offline
Зарегистрирован: 12.09.2015

Поругайте код, пожалуйста

#include "DHT.h"  // подключаем все библиотеки
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Time.h>
#include <Wire.h>
#include <DS1307RTC.h>
#include <EEPROM.h>

#define ONE_WIRE_BUS 4 //номер пина ds18b20
#define DHTPINa 2 // номер пина первого dht22
#define DHTPINb 3 // номер пина второго dht22

OneWire oneWire(ONE_WIRE_BUS); //создаем обьект для ds18b20

DHT dhta(DHTPINa, DHT22); // и для dht22
DHT dhtb(DHTPINb, DHT22); 

DallasTemperature sensors(&oneWire);
DeviceAddress Thermometer1 = { 0x28, 0xFF, 0xEE, 0xBB, 0x62, 0x15, 0x01, 0x92 }; //адрес термометра
  
int addressWrite = 0; // переменная для записи
int addressRead = 0; // переменная для чтения
byte value; // переменная значения ячейки
int x; // переменная-счетчик записи в ячейку
int buttonState = digitalRead(12); // переменная состояния кнопки

void setup() 
{
  x=0;                  // при включении обнуляем счетчик записи 
  pinMode(12, INPUT); // 12 пин для кнопки
  pinMode(13, OUTPUT);  //для светодиода

  sensors.begin(); // запускаем датчики
  sensors.setResolution(Thermometer1, 8); // и задаем разрешение датчика
  dhta.begin();
  dhtb.begin();
  
  Serial.begin(9600); // и запускаем ком-порт


  setSyncProvider(RTC.get); // и время
}

void loop() 
{
  sensors.requestTemperatures();  // запрашиваем данные с датчиков
  float h1 = dhta.readHumidity();
  float h2 = dhtb.readHumidity();
  float t3 = sensors.getTempC(Thermometer1);
  delay(100);                       // не знаю точно зачем тут дилэй, но вроде бы желательно ему тут быть
  float t1 = dhta.readTemperature();
  delay(100);
  float t2 = dhtb.readTemperature();
  delay(100);

  if (isnan(h1) || isnan(t1) || isnan(h2) || isnan(t2) || isnan (t3) ) // на случай если не удалось считать данные с датчика - помигает диодом
    {
    digitalWrite(13, HIGH);
    delay(500);
    digitalWrite(13, LOW);
    delay(500);
    digitalWrite(13, HIGH);
    delay(500);
    digitalWrite(13, LOW);
    delay(500);
    digitalWrite(13, HIGH);
    delay(500);
    digitalWrite(13, LOW);
    delay(500);
    return;
    }

  byte humydity; // переменная для средней влажности
  humydity = ((h1+h2)/2);

  if (humydity <= 0 || humydity >= 100) // проверим чтобы она была в рамках относительной влажности
  return;

  while (buttonState == HIGH) // если нажата кнопка
    {
    value = EEPROM.read(addressWrite);// то выводим в ком-порт данные
    Serial.print("Archive of temperature and humidity: ");
    Serial.print(value, DEC);                                   // первая ячейка - число
    Serial.print(".");
    addressWrite = addressWrite + 1;

    value = EEPROM.read(addressWrite);
    Serial.print(value, DEC);
    Serial.print(".");                                         // вторая - месяц
    addressWrite = addressWrite + 1;

    value = EEPROM.read(addressWrite);
    Serial.print(value + 2000, DEC);                           // третья - год, чтобы влезло в один байт, при записи отнимаем 2000, при чтении добавляем
    addressWrite = addressWrite + 1;
    Serial.print("\t");

    value = EEPROM.read(addressWrite);
    Serial.print(value, DEC);                                  // четвертая - час записи.
    addressWrite = addressWrite + 1;
    Serial.print(":00\n");
  
    value = EEPROM.read(addressWrite);
    Serial.print("The temperature at a height of 1.5 meters: ");
    Serial.print(value-127, DEC);                                 // пятая - температура с первого DHT22, -127 - чтобы иметь возможность писать отрицательные температуры, при записи 
    Serial.print(" Celsius");                                     // берем значение 127 за 0 градусов.
    addressWrite = addressWrite + 1;
    Serial.print("\n");
  
    value = EEPROM.read(addressWrite);
    Serial.print("The temperature at a height of 6 meters: ");
    Serial.print(value-127, DEC);                                 // шестая - температура с второго DHT22
    Serial.print(" Celsius");
    addressWrite = addressWrite + 1;
    Serial.print("\n");

    value = EEPROM.read(addressWrite);
    Serial.print("The temperature at a height of 9 meters: ");
    Serial.print(value-127, DEC);
    Serial.print(" Celsius");                                 // седьмая - температура с ds18b20
    addressWrite = addressWrite + 1;
    Serial.print("\n");

    value = EEPROM.read(addressWrite);
    Serial.print("Average humidity: ");
    Serial.print(value, DEC);                                 // восьмая - средняя влажность
    Serial.print(" %");
    addressWrite = addressWrite + 1;
    Serial.print("\n");
    Serial.print("\n");

    if(addressWrite == EEPROM.length())                        // если достигли конца EEPROM - начинаем сначала
    addressWrite = 0; 
    }
 


  if (x == 0 && hour() == 8 && minute() == 0 )                              // условия для записи, одна запись в нужную минуту
  {
   digitalWrite(13, HIGH);                                                  //моргнем светодиодом пока пишем, для визуального контроля
   EEPROM.write(addressWrite, day());
   addressWrite = addressWrite + 1;                                        // переход на следующий адрес
   if (addressWrite == 1024)                                               // если заполнилось - начинаем сначала
    addressWrite = 0;
   delay(50);                                                              // на всякий случай
   
   EEPROM.write(addressWrite, month());
   addressWrite = addressWrite + 1;
   if (addressWrite == 1024)
    addressWrite = 0;
   delay(50);

   byte yearwrite= year() - 2000;                                          //отдельная переменная типа байт для записи в EEPROM
   EEPROM.write(addressWrite, yearwrite);
   addressWrite = addressWrite + 1;
   if (addressWrite == 1024)
    addressWrite = 0;
   delay(50);
   
   EEPROM.write(addressWrite, hour());
   addressWrite = addressWrite + 1;
   if (addressWrite == 1024)
    addressWrite = 0;
   delay(50);
   
   byte twrite1 = t1+127;                                                      //тоже самое, байт для записи в EEPROM, прибавляем 127 для отрицательных чисел
   EEPROM.write(addressWrite, twrite1);
   addressWrite = addressWrite + 1;
   if (addressWrite == 1024)
    addressWrite = 0;
   delay(50);
   
   byte twrite2 = t2+127;
   EEPROM.write(addressWrite, twrite2);
   addressWrite = addressWrite + 1;
   if (addressWrite == 1024)
    addressWrite = 0;
   delay(50);

   byte twrite3 = t3+127;
   EEPROM.write(addressWrite, twrite3);
   addressWrite = addressWrite + 1;
   if (addressWrite == 1024)
    addressWrite = 0;
   delay(50);
   
   EEPROM.write(addressWrite, humydity);
   addressWrite = addressWrite + 1;
   if (addressWrite == 1024)
    addressWrite = 0;
   delay(50);
   x++;
   digitalWrite(13, LOW);                                                     // выключаем светодиод
  }
  if ( x > 0 && hour() == 8 && minute() == 1 )                                // когда прошла первая минута - обнуляем счетчик, не сделали это сразу чтобы не было несколько записей                  
  x =0;                                                                       // в одну и ту же минуту
  delay(100);
}

Память расходуется, конечно, безбожно, но зато все наглядно, что для меня важно, пока что. 

Да и 64 дня для меня - с головой, если раз в месяц снимать данные.

Правда меня смущает что в таком случае первые ячейки еепрома будут изнашиваться быстрее чем последние, как в таком случае сделать - сделать чтобы значение последнего адреса он хранил в отдельной ячейке еепрома?

А еще не понимаю почему при включении кнопки код на чтение в монитор порта сразу не срабатывает - только после ребута ?

И так же интересует - если ли какой-то метод перевода из float в byte без создания еще одной переменной типа byte ? Или же оно само округлится до целых при записи?

 

Tomasina
Tomasina аватар
Offline
Зарегистрирован: 09.03.2013

Мужик из полиуретана пишет:
И так же интересует - если ли какой-то метод перевода из float в byte без создания еще одной переменной типа byte ? Или же оно само округлится до целых при записи?

Просто перед переменной принудительно указать нужный тип:

EEPROM.write(addressWrite, (byte) t1 + 127);