Как большинство работающих людей, занятие собственными проектами отнимает единственно оставшееся свободное время. Поэтому уже давно не творил и «чесались руки» что-либо сделать. Данная возможность появилась как ни странно в университете. За окном сентябрь, 4 курс и надвигающийся курсовой по схемотехнике. Нам сказали, что курсовые можно будет делать в двух вариациях: бумажном и «железе».

На протяжении 5 лет бумажный курсовой в нашем университете делался по принципу «возьми старые и собери их воедино». Такой подход меня не устраивал своей рутинностью, поэтому я сразу же выбрал курсовой в «железе». В качестве сердца курсовых был предложен микроконтроллер Arduino ввиду своей легкообучаемости. После определения с типом курсового оставался ещё один вопрос: а что именно бы сделать. Так как опыта в программировании микроконтроллеров не было, то сразу же открыл гугл и начал изучать существующие проекты. Проектов много, некоторые из них довольно простые, некоторые гениальны (3D сканер, например), но подавляющее большинство не имело практического применения. А мне хотелось именно того, что не валялось бы потом на полке и не собирало там пыль. После получасового экскурса в мир Arduino, меня заинтересовало тема домашних метеостанций, да и проекты показались не очень сложными в реализации (что в основном и подкупило новичка).

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

Выбор компонентов

Просматривая разные проекты я понимал, что мне вполне достаточно будет Nano или даже Pro Mini, но всё-таки выбрал Arduino Uno в надежде, что программирование для Arduino мне понравится и в дальнейшем реализую ещё какие-нибудь проекты. Паяльник до этого в руках ни разу не держал, поэтому для более легкой разработки решил также приобрести Sensor Shield v4.

Подробнее

Плата способствует быстрому подключению датчиков, модулей, серво моторов, интерфейсов Serial и I2C, а также выводит все порты контроллера формфактора Duemilanova/Uno(также может быть подключена и в серию мега, но с ограничениями и вытекающими последствиями). Поддерживает другие шилды поверх себя.


В качестве источников для метеорологических данных выбрал следующие датчики:


С датчиками определился. Но что делать с данными, поступающими от датчиков. Решил выводить на дисплей. Картинку хотелось цветную, поэтому монохромные решения отбросил сразу. После нескольких минут поиска был выбран TFT дисплей ST7735 размером 1,8 дюймов.

Подробнее

Поскольку дисплей использует 4-проводной SPI протокод для связи и имеет свой собственный пикселе-адресуемый буфер кадра, он может использоваться с любыми видами микроконтроллеров. 1.8-дюймовый дисплей имеет 128x160 цветных пикселя. Также имеется слот для карты памяти microSD, следовательно, можно легко загружать полноцветные растровые изображения из FAT16 / FAT32 файловой системы microSD карты.

Характеристики:

  • Диагональ дисплея - 1.8 дюймов, разрешение 128x160 пикселей, 18-битный цвет (262 144 цвета)
  • Контроллер со встроенной пиксельной адресацией буфера видеопамяти
  • Встроенный слот для microSD - использует более 2 цифровых линий
  • Совместим с 3.3 и 5V
  • Габариты: 34 мм х 56 мм х 6,5 м


Программирование контроллера Arduino

После того, как определились с компонентами для метеостанции, начнём программирование контроллера. Для прошивки Arduino использовалась среда разработки Arduino IDE. Также использовал библиотеки от Adafruit.

Перед тем, как перейти к скетчу, рассмотрим функционал:

  • Показания снимаются с датчиков каждые 10 секунд и обновляются на экране только те показатели, которые были изменены по сравнению с прошлым измерением
  • Реализована передача данных по COM порту

Скетч

#include // library for communication with I2C devices #include // Core library for all sensors #include // library for BMP180 #include // Core graphics library #include // Hardware-specific library #include // library for communication with SPI devices #include "dht.h" // library for DHT #define DHT22_PIN 2 // connect data pin of DHT22 to 2 digital pin #define TFT_CS 10 // connect CS pin of TFT to 10 digital pin #define TFT_RST 9 // connect RST pin of TFT to 9 digital pin // you can also connect this to the Arduino reset // in which case, set this #define pin to 0! #define TFT_DC 8 // connect DC pin of TFT to 8 digital pin Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST); //initialize TFT #define TFT_SCLK 13 // connect SCLK pin of TFT to 13 digital pin #define TFT_MOSI 11 // connect MOSI pin of TFT to 11 digital pin dht DHT; Adafruit_BMP085_Unified bmp = Adafruit_BMP085_Unified(10085); //initialize BMP180 int bmpFlag = 0; struct { uint32_t total; uint32_t ok; uint32_t crc_error; uint32_t time_out; uint32_t connect; uint32_t ack_l; uint32_t ack_h; uint32_t unknown; } stat = { 0,0,0,0,0,0,0,0}; // struct for dht status void setup(void) { Serial.begin(9600); Serial.println("Meteo Test"); Serial.println(""); if(!bmp.begin()) // check connection for BMP180 { Serial.print("Ooops, no BMP180 detected ... Check your wiring or I2C ADDR!"); bmpFlag = 1; } tft.initR(INITR_BLACKTAB); // Initialize TFT and fill with black color tft.fillScreen(ST7735_BLACK); tft.setRotation(tft.getRotation() + 1); tft.setTextSize(1.5); delay(500); // delay in order to ensure that TFT was initialized } // last measured data float oldTemperature = 0, oldAltitude = 0, oldPressure = 0, oldDHTHumidity = 0, oldDHTTemperature; bool wasUpdate = false; void loop(void) { if(Serial.available() > 0) // we have data is Serial port { Serial.read(); // read byte from serial port and send last measured data printValue("Pressure", oldPressure, " hPa", false); printValue("Temperature", oldTemperature, " C", false); printValue("Altitude", oldAltitude, " m", false); printValue("Humidity", oldDHTHumidity, "%", false); printValue("DHT_temperature", oldDHTTemperature, " C", false); Serial.println("END_TRANSMISSION"); } sensors_event_t event; float temperature, altitude; if(bmpFlag == 0){ bmp.getEvent(&event); // get data from BMP180 if (event.pressure) { bmp.getTemperature(&temperature); float seaLevelPressure = SENSORS_PRESSURE_SEALEVELHPA; altitude = bmp.pressureToAltitude(seaLevelPressure, event.pressure, temperature); } else { Serial.println("Sensor error"); } } uint32_t start = micros(); int chk = DHT.read22(DHT22_PIN);// get data from DHT22 uint32_t stop = micros(); stat.total++; switch (chk) // check status of DHT22 { case DHTLIB_OK: stat.ok++; break; case DHTLIB_ERROR_CHECKSUM: stat.crc_error++; Serial.print("Checksum error,\t"); break; case DHTLIB_ERROR_TIMEOUT: stat.time_out++; Serial.print("Time out error,\t"); break; case DHTLIB_ERROR_CONNECT: stat.connect++; Serial.print("Connect error,\t"); break; case DHTLIB_ERROR_ACK_L: stat.ack_l++; Serial.print("Ack Low error,\t"); break; case DHTLIB_ERROR_ACK_H: stat.ack_h++; Serial.print("Ack High error,\t"); break; default: stat.unknown++; Serial.print("Unknown error,\t"); break; } if(bmpFlag != 0 || !event.pressure) // update data { tft.fillRect(0, 30, 160, 6, ST7735_BLACK); tft.setCursor(0, 30); tft.setTextColor(ST7735_RED); printValue("ERROR BMP INITIALIZATION", 0, "", true); } else { if(event.pressure != oldPressure) { tft.fillRect(0, 30, 160, 7, ST7735_BLACK); tft.setCursor(0, 30); tft.setTextColor(ST7735_RED); printValue("Pressure", event.pressure, " hPa", true); oldPressure = event.pressure; wasUpdate = true; } if(temperature != oldTemperature) { tft.fillRect(0, 38, 160, 7, ST7735_BLACK); tft.setCursor(0, 38); tft.setTextColor(ST7735_WHITE); printValue("Temperature", temperature, " C", true); oldTemperature = temperature; wasUpdate = true; } if(altitude != oldAltitude) { tft.fillRect(0, 46, 160, 7, ST7735_BLACK); tft.setCursor(0, 46); tft.setTextColor(ST7735_BLUE); printValue("Altitude", altitude, " m", true); oldAltitude = altitude; wasUpdate = true; } } if(DHT.humidity != oldDHTHumidity) { tft.fillRect(0, 54, 160, 7, ST7735_BLACK); tft.setCursor(0, 54); tft.setTextColor(ST7735_GREEN); printValue("Humidity", DHT.humidity, "%", true); oldDHTHumidity = DHT.humidity; wasUpdate = true; } if(DHT.temperature != oldDHTTemperature) { tft.fillRect(0, 80, 160, 7, ST7735_BLACK); tft.setCursor(0, 80); tft.setTextColor(ST7735_YELLOW); printValue("DHT_temperature", DHT.temperature, " C", true); oldDHTTemperature = DHT.temperature; wasUpdate = true; } if(wasUpdate) { Serial.println("END_TRANSMISSION"); } wasUpdate = false; delay(10000); } void printValue(char* title, double value, char* measure, bool tftPrint) { if(tftPrint) // print data to TFT { tft.print(title); tft.print(": "); tft.print(value); tft.println(measure); } Serial.print(title); // send data to Serial port Serial.print(": "); Serial.print(value); Serial.println(measure); }

Самое время собрать корпус

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

В местном магазине радиоэлектроники был приобретён корпус.

Корпус

(На фото корпус немного не такой. У меня крышка прозрачная)



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

Корпус с отверстиями для датчиков и питания



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

Система перед "запихиванием" в корпус



Так как корпус намного больше Arduino (меньше не было), пришлось придумывать подпорку, чтобы плата не ездила внутри корпуса. Также из паралона была вырезана фигура, а в ней прямоугольник для экрана с целью скрыть внутренности корпуса. Суперклея под рукой не было, поэтому пришлось садить на двусторонний скотч.

Чудо-юда рыба-кит



Прикручиваем крышку, подключаем питание и ждём.

Законченная метеостанция в корпусе



После вывода результатов на экран, выявляем неприятную ошибку измерения влажности: DHT22 усердно выдаёт цифру 99,90% (крайне редко бывает 1,00%). Начинаем разбираться в чём проблема. Первое, что делаем - смотрим вывод значений в COM порт. Вроде всё нормально. После нексольких перезаливок, разборок и сборок корпуса в голову приходит мысль поискать ответ в гугле. Как и ожидалось русский гугл ничего дельного не сказал. Окей. Начинаем искать на английском и на одном из форумов натыкаемся на ребят с похожей проблемой. Первые четыре страницы обсуждения ничего дельного не дают, а на пятой странице находим ответ на наш вопрос:
Humidity sensors can easily be affected by the wrong gasses or very long exposure to high humidity IIRC. In the datasheet there is a procedure how to «reset» the sensor, you could give it a try.

Оставался вопрос только в том, когда и как я успел навредить DHT22. Но подходило время сдавать курсовой и поэтому я оставил решение этой проблемы на потом.

Послесловие

Курсовой был сдан. Метеостанция отложена на неопределенное время до закрытия всех хвостов в университете. Однако, к метеостанции пришлось вернутся раньше, чем я думал. Так сложилось, что в середине ноября я поменял рабочее место и в новой команде я познакомился с людьми, которые интересуются платформой Arduino и им подобными. Поэтому мой интерес к данной платформе не успев остыть, разгорелся снова. Я достал свою метеостанцию, подключил к компьютеру и вспомнил, что я реализовывал передачу данных с Arduino по COM порту. И тут мне пришла в голову идея, написать программу, принимающую данные через COM порт от Arduino и передавать эти данные на народный мониторинг , но это уже совсем другая история.

Также хотелось бы иметь беспроводные датчики и всё-таки реализовать метеостанцию на Arduino Pro Mini. Поэтому мною были заказаны 4 Arduino Pro Mini с питанием 3,3В, 4 радиомодуля nRF24L01+ и ещё кое-какие дополнительные датчики, о чём я также постараюсь рассказать в следующий раз. А пока я жду посылки, в планах реализовать подключение часов реального времени для возможности сохранения времени обновления данных и самих данных на microSD карту при условии отсутствия соединения с клиентом по COM порту.

Вы можете помочь и перевести немного средств на развитие сайта



Захотелось иметь свою метеостанцию, которая передает показания с датчиков на карту народного мониторинга (ищется в гугле за 5 секунд). Оказалось это не так сложно, как кажется. Рассмотрим, что было сделано.

Для данного действия я взял себе Arduino Uno и Ethernet Shield w5100 для нее. Все это заказывалось из Китая на Aliexpress.

Так же там заказал себе датчики: DHT22, DHT11, DS18B20, BMP280 (в планах еще датчики газа, дыма…)

Покурив форумы, гугл, яндекс, я нашел неплохой вариант скетча — https://student-proger.ru/2014/11/meteostanciya-2-1/

Там же в комментариях человек выкладывал дописанный скетч с датчиками освещенности, газа. Я взял их за основу.

В тех скетчах не было поддержки 280-го датчика давления, пообщались с автором, он заменил 180 на 280. Все заработало прекрасно (спасибо ему за это огромное)

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

В данный момент у меня подключены датчики:
DHT22 — 1шт.
DHT11 — 1шт.
BMP280 — 1шт.
DS18B20 — 2шт.

ВНИМАНИЕ! Перед тем как заливать скетч, не забудьте изменить MAC-адрес устройства, чтобы не пересекаться с другими (например взять Mac-адрес вашего мобильного телефона и изменить в нем последние буквы/цифры, что не «будоражило» вашу локальную сеть!

Примерная схема подключения (картинка взята на просторах интернета от данного скетча):

По техническим причинам у меня не получается выложить скетч прямо сюда. Поместил его в архив. Ссылка на него строчкой выше.

Как видно, показания есть, идут исправно, для примера выложу пару скриншотов со своих датчиков:

Загружать прошивку желательно до подключения компонентов, чтобы убедиться в том, что плата рабочая. После сборки можно прошить ещё раз, плата должна спокойно прошиться. В проектах с мощными потребителями в цепи питания платы 5V (адресная светодиодная лента, сервоприводы, моторы и проч.) необходимо подать на схему внешнее питание 5V перед подключением Arduino к компьютеру, потому что USB не обеспечит нужный ток, если например лента его потребует. Это может привести к выгоранию защитного диода на плате Arduino. Гайд по скачиванию и загрузке прошивки можно найти под спойлером на следующей строчке.

Содержимое папок в архиве

  • libraries – библиотеки проекта. Заменить имеющиеся версии
  • firmware – прошивки для Arduino
  • schemes – схемы подключения компонентов

Дополнительно

  • Как показал эксперимент, снаружи корпуса датчик температуры показывает на 0.5 градуса меньше, чем внутри! Нужно более удачно компоновать электронику, отводить и экранировать тепло от греющихся элементов…

  • Если дисплей показывает слишком тускло/на белом фоне
    На плате драйвера дисплея (к которой подключаются провода) есть крутилка контрастности, с её помощью можно подстроить контраст на нужный. Также контрастность зависит от угла взгляда на дисплей (это же LCD) и можно настроить дисплей на чёткое отображение даже под углом “дисплей на уровне пупка, смотрим сверху”. А ещё контрастность сильно зависит от питания: от 5V дисплей показывает максимально чётко и ярко, тогда как при питании от USB через Arduino напряжение будет около 4.5V (часть падает на защитном диоде по линии USB), и дисплей показывает уже не так ярко. Вывод настраивайте крутилкой при внешнем питании от 5V!

  • Если датчик CO2 работает некорректно (инфа от Евгения Иванова)
    Ну там в папке библиотеки сенсора в examples есть скетчи для калибровки. также ее можно запустить втупую замкнув на землю разъем “HD” на 7+ секунд.
    Само собой вот прямо на улице на морозе этим заниматься не обязательно… можно просто в бутылку набрать свежего воздуха с датчиком внутри и запечатать. калибровка проводится минимум 20 минут..
    По-умолчанию датчик поставляется с включенной автокалибровкой, которая происходит каждый день, и если датчик используется в невентелируемом помещении, то эта калибровка быстро уводит значения от нормы за горизонт, потому ее нужно обязательно отключать.
    Документация .

  • Автокалибровка датчика CO2 отключена в скетче!

  • Если у вас не работает датчик BME280 , скорее всего у него отличается адрес. В проекте используется библиотека Adafruit_BME280, у которой нет отдельной функции смены адреса, поэтому адрес задаётся вручную в файле библиотеки Adafruit_BME280.h почти в самом начале файла (лежит в папке Adafruit_BME280 в вашей папке библиотек, вы должны были её туда установить ), у моего модуля был адрес 0x76. Как узнать адрес своего модуля BME280? Есть специальный скетч, называется i2c scanner. Его можно нагуглить, можно . Прошиваете данный скетч, открываете порт и получаете список адресов подключенных к шине i2c устройств. Чтобы остальные модули вам не мешали – можно их отключить и оставить только BME280. Полученный адрес указываем в библиотеке, сохраняем файл и загружаем прошивку метео-часов. Всё!

  • Если отстают часы , проблема скорее всего в питании схемы. Если при смене блока питания на более качественный проблема не уходит, повесьте конденсатор по питанию RTC модуля (прям на плату на VCC и GND паять): обязательно керамический, 0.1-1 мкФ (маркировка 103 или 104, смотрите таблицу маркировок). Также можно поставить электролит (6.3V, 47-100 мкФ)

Настройки в прошивке

#define RESET_CLOCK 0 // сброс часов на время загрузки прошивки (для модуля с несъёмной батарейкой). Не забудь поставить 0 и прошить ещё раз! #define SENS_TIME 30000 // время обновления показаний сенсоров на экране, миллисекунд #define LED_MODE 0 // тип RGB светодиода: 0 - главный катод, 1 - главный анод #define LED_BRIGHT 255 // яркость светодиода СО2 (0 - 255) #define BLUE_YELLOW 1 // жёлтый цвет вместо синего (1 да, 0 нет) но из за особенностей подключения жёлтый не такой яркий #define DISP_MODE 1 // в правом верхнем углу отображать: 0 - год, 1 - день недели, 2 - секунды #define WEEK_LANG 1 // язык дня недели: 0 - английский, 1 - русский (транслит) #define DEBUG 0 // вывод на дисплей лог инициализации датчиков при запуске #define PRESSURE 1 // 0 - график давления, 1 - график прогноза дождя (вместо давления). Не забудь поправить пределы гроафика // пределы отображения для графиков #define TEMP_MIN 15 #define TEMP_MAX 35 #define HUM_MIN 0 #define HUM_MAX 100 #define PRESS_MIN -100 #define PRESS_MAX 100 #define CO2_MIN 300 #define CO2_MAX 2000

2018-06-18 в 15:08

Данная погодная станция обеспечивает постоянное получение сведений о состоянии погодных условий. Проект основан на плате микроконтроллеров Arduino, а данные выводятся на LCD экран. Ранее был проект вывода данных с датчиков на веб-страницу с помощью W5100 . Небольшой размер "железа" позволяет поместить устройство в маленьком пластиковом коробе, части которого изготовлены при помощи лазерной резки.

Датчик уровня воды и снега.
Индикатор уровня воды используется для вывода уровня воды в баке во избежании его переполнения.

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

Фоторезисторы, также известные как светозависимые резисторы (LDR), являются светочувствительными устройствами, наиболее часто используемыми для определения наличия или отсутствия света, или для измерения интенсивности света. В темноте их сопротивление очень велико, но когда датчик LDR подвергается воздействию света, сопротивление резко падает, вплоть до нескольких Ом.

LCD1602 с шиной I2C. Синий потенциометр на ЖК-дисплее I2C 1602 используется только для подсветки.

I2C использует только две линии, Serial DataLine (SDA) и Serial Clock Line (SCL), которые подключаются к резисторам. Типичные напряжения - +5 В или +3,3 В, хотя допускаются системы с другими напряжениями.

DS1302 - часики реального времени.
Часы основаны на интегрированной микросхеме DS1302, внутри которой есть часы / календарь в реальном времени и 31 байт статической ОЗУ. Формат времени можно увидеть как hh/mm/ss, а формат даты - yyyy/mm/dd. Так же можно высчитать день недели.

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

Инфракрасный приемник и пульт дистанционного управления

Эти два компонента работают вместе: ИК-приемник позволяет получать данные с пульта дистанционного управления. Уже рассказывал как собрать контроллер вытяжки с управлением от пульта телевизора. Данные зависят от того, какую кнопку вы хотите нажать. Были выбраны следующие кнопки для назначения их определенным функциям:

Клавиша 0 - позволяет увидеть время и дату

Клавиша 1 - позволяет увидеть данные с датчиков DHT11 и LM35

Клавиша 2 - позволяет увидеть в процентах уровень освещенности

Клавиша 3 - позволяет увидеть в миллиметрах уровень жидкости

Клавиша "Повтор" - прокручивает все окна с интервалом в 4 секунды

Сборка корпуса.
Рассмотрев размер устройства, мы продолжили строительство корпуса из плексигласа. Размеры сторон с их взаимными блокирующими сиденьями и отверстиями для выхода проводов датчиков были рассчитаны с помощью программного обеспечения Autocad, после чего мы занялись вырезанием, используя машину для лазерной резки. И, наконец, мы собрали все с помощью мощного клея.
Файл исходник - Скачать.

Схема устройства была сделана в программной среде fritzing ().

Разрабатывали код в среде Arduino IDE, использовали все необходимые библиотеки. И вот что у нас получилось:

Это главный экран, который пользователь может видеть, когда мы включаем плату. При включении появляется надпись «Arduino Weather Station». Вы также можете увидеть эту надпись после каждого обращения к AWS.

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

Экран, который показывает данные, полученные датчиками DHT11 и LM35 относительно влажности и температуры соответственно. Он "привязан" к кнопке 1 на пульте дистанционного управления, и когда она нажимается, экран имеет задержку в 10 секунд, а затем возвращается на главный экран.

Экран уровень освещенности. Привязан к кнопке 2 на пульте ДУ.

Этот экран показывает уровень жидкости в баке. Он подключен к кнопке 3 на пульте дистанционного управления.

Сама программа станции

//include sketch libraries #include #include //clock library #include //clock library #include //clock library #include //dht11 library #include //LCD library #include //Wire for LCD library #define lmPin A1 //LM35 attach to A1 LiquidCrystal_I2C lcd(0x27 , 16 , 2 ); // set the LCD address to 0x27 for a 16 chars and 2 line display dht DHT; //create a variable type of dht const int DHT11_PIN = 4 ; //attach dht11 to pin 4 const int waterSensor = 0 ; //set water sensor variable int waterValue = 0 ; //variable for water sensor int mmwaterValue = 0 ; int sensorPin = A3; // select the input pin for the potentiometer int luce = 0 ; //variable for the ldr int pluce = 0 ; //variable for the ldr float tem = 0 ; //variable for the temperature long lmVal = 0 ; //variable for the LM35 //ir const int irReceiverPin = 3 ; IRrecv irrecv(irReceiverPin); //Creates a variable of type IRrecv decode_results results; //define clock variable uint8_t RST_PIN = 5 ; //RST pin attach to uint8_t SDA_PIN = 6 ; //IO pin attach to uint8_t SCL_PIN = 7 ; //clk Pin attach to /* Create buffers */ char buf; char day; /* Create a DS1302 object */ DS1302 rtc(RST_PIN, SDA_PIN, SCL_PIN);//create a variable type of DS1302 void print_time() { /* Get the current time and date from the chip */ Time t = rtc.time(); /* Name the day of the week */ memset(day, 0 , sizeof (day)); switch (t.day) { case 1 : strcpy(day, "Sun" ); break ; case 2 : strcpy(day, "Mon" ); break ; case 3 : strcpy(day, "Tue" ); break ; case 4 : strcpy(day, "Wed" ); break ; case 5 : strcpy(day, "Thu" ); break ; case 6 : strcpy(day, "Fri" ); break ; case 7 : strcpy(day, "Sat" ); break ; } /* Format the time and date and insert into the temporary buffer */ snprintf(buf, sizeof (buf), "%s %04d-%02d-%02d %02d:%02d:%02d" , day, t.yr, t.mon, t.date, t.hr, t.min , t.sec); /* Print the formatted string to serial so we can see the time */ Serial .println (buf); lcd.setCursor (2 , 0 ); lcd.print (t.yr); lcd.print ("-" ); lcd.print (t.mon / 10 ); lcd.print (t.mon % 10 ); lcd.print ("-" ); lcd.print (t.date / 10 ); lcd.print (t.date % 10 ); lcd.print (" " ); lcd.print (day); lcd.setCursor (4 , 1 ); lcd.print (t.hr); lcd.print (":" ); lcd.print (t.min / 10 ); lcd.print (t.min % 10 ); lcd.print (":" ); lcd.print (t.sec / 10 ); lcd.print (t.sec % 10 ); } void setup () { //clock Serial .begin (9600 ); rtc.write_protect(false); rtc.halt(false); //ir irrecv.enableIRIn(); //enable ir receiver module lcd.init(); //initialize the lcd lcd.backlight(); //open the backlight pinMode (sensorPin, INPUT ); Time t(2017 , 12 , 03 , 10 , 15 , 00 , 1 );//initialize the time /* Set the time and date on the chip */ rtc.time(t); } void loop () { lcd.setCursor (0 , 0 ); lcd.print ("A" ); delay (50 ); lcd.setCursor (1 , 0 ); lcd.print ("r" ); delay (50 ); lcd.setCursor (2 , 0 ); lcd.print ("d" ); delay (50 ); lcd.setCursor (3 , 0 ); lcd.print ("u" ); delay (50 ); lcd.setCursor (4 , 0 ); lcd.print ("i" ); delay (50 ); lcd.setCursor (5 , 0 ); lcd.print ("n" ); delay (50 ); lcd.setCursor (6 , 0 ); lcd.print ("o" ); delay (50 ); lcd.setCursor (8 , 0 ); lcd.print ("W" ); delay (50 ); lcd.setCursor (9 , 0 ); lcd.print ("e" ); delay (50 ); lcd.setCursor (10 , 0 ); lcd.print ("a" ); delay (50 ); lcd.setCursor (11 , 0 ); lcd.print ("t" ); delay (50 ); lcd.setCursor (12 , 0 ); lcd.print ("h" ); delay (50 ); lcd.setCursor (13 , 0 ); lcd.print ("e" ); delay (50 ); lcd.setCursor (14 , 0 ); lcd.print ("r" ); delay (50 ); lcd.setCursor (4 , 1 ); lcd.print ("S" ); delay (50 ); lcd.setCursor (5 , 1 ); lcd.print ("t" ); delay (50 ); lcd.setCursor (6 , 1 ); lcd.print ("a" ); delay (50 ); lcd.setCursor (7 , 1 ); lcd.print ("t" ); delay (50 ); lcd.setCursor (8 , 1 ); lcd.print ("i" ); delay (50 ); lcd.setCursor (9 , 1 ); lcd.print ("o" ); delay (50 ); lcd.setCursor (10 , 1 ); lcd.print ("n" ); delay (50 ); if (irrecv.decode(&results)) //if the ir receiver module receiver data { if (results.value == 0xFF6897 ) //if "0" is pushed print TIME { lcd.clear (); //clear the LCD print_time(); lcd.clear (); //clear the LCD } if (results.value == 0xFF30CF ) //if "1" is pushed print TEMPERATURE and HUMIDITY { lcd.clear (); //clear the LCD //READ DATA of the DHT // DISPLAY DATA lcd.setCursor (0 , 0 ); lcd.print ("Tem:" ); lmVal = analogRead (lmPin);//read the value of A1 lcd.print (tem);//print tem lcd. lcd.print ("C " ); // Serial.println(" C"); lcd.setCursor (0 , 1 ); lcd.print ("Hum:" ); //Serial.print("Hum:"); lcd. lcd.print (" % " ); //Serial.println(" %"); delay (10000 ); //wait for 3000 ms lcd.clear (); //clear the LCD irrecv.resume(); // Receive the next value } if (results.value == 0xFF18E7 ) //if "2" is pushed print the DARKNESS { lcd.clear (); //clear the LCD lcd.setCursor (4 , 0 ); lcd.print ("Darkness:" ); luce = pluce = lcd.setCursor (6 , 1 ); lcd. lcd. delay (10000 ); //delay 10000 ms lcd.clear (); //clear the LCD delay (200 ); //wait for a while irrecv.resume(); // Receive the next value } if (results.value == 0xFF7A85 ) //if "3" is pushed print the SNOW or WATER LEVEL { lcd.clear (); //clear the LCD lcd.setCursor (0 , 0 ); lcd. lcd.setCursor (6 , 1 ); mmwaterValue = lcd. delay (10000 ); //delay 10000ms lcd.clear (); //clear the LCD delay (200 ); irrecv.resume(); // Receive the next value } if (results.value == 0xFF9867 ) //if "PRESENTATION" is pushed print TIME, TEM and HUM, DARKNESS and S or W LEVEL one time { lcd.clear (); //clear the LCD print_time(); lcd.clear (); //clear the LCD delay (200 ); //wait for a while //READ DATA of the DHT int chk = DHT.read11(DHT11_PIN); // DISPLAY DATA lcd.setCursor (0 , 0 ); lcd.print ("Tem:" ); lmVal = analogRead (lmPin);//read the value of A0 tem = (lmVal * 0.0048828125 * 100 );//5/1024=0.0048828125;1000/10=100 lcd.print (tem);//print tem lcd.print (char (223 ));//print the unit" ? " lcd.print ("C " ); // Serial.println(" C"); lcd.setCursor (0 , 1 ); lcd.print ("Hum:" ); //Serial.print("Hum:"); lcd.print (DHT.humidity, 1 ); //print the humidity on lcd //Serial.print(DHT.humidity,1); lcd.print (" % " ); //Serial.println(" %"); delay (4000 ); //wait for 3000 ms lcd.clear (); //clear the LCD delay (200 ); //wait for a while lcd.setCursor (4 , 0 ); //place the cursor on 4 column, 1 row lcd.print ("Darkness:" ); luce = analogRead (sensorPin); //read the ldr pluce = map (luce, 0 , 1023 , 0 , 100 ); //the value of the sensor is converted into values from 0 to 100 lcd.setCursor (6 , 1 ); //place the cursor on the middle of the LCD lcd.print (pluce); //print the percentual lcd.print ("%" ); //print the symbol delay (4000 ); //delay 10000 ms lcd.clear (); //clear the LCD delay (200 ); //wait for a while lcd.setCursor (0 , 0 ); //place the cursor on 0 column, 1 row lcd.print ("Fluid level(mm):" ); //print "Fluid level(mm):" int waterValue = analogRead (waterSensor); // get water sensor value lcd.setCursor (6 , 1 ); //place cursor at 6 column,2 row mmwaterValue = map (waterValue, 0 , 1023 , 0 , 40 ); lcd.print (mmwaterValue); //value displayed on lcd delay (4000 ); //delay 10000ms lcd.clear (); //clear the LCD delay (200 ); irrecv.resume(); // Receive the next value } } }

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

Не пропустите обновления! Подписывайтесь на нашу группу

В свободное время, и на этот раз написал инструкцию по изготовления небольшой метеостанции. Она будет выполнять функцию часов с датой и показывать температуры внутри и снаружи помещения. Как основной контролер будем использовать Arduino UNO, но подойдет и другая плата с Atmega328p на борту. Для отображения используем графический экран WG12864B. Также подключим два датчика температуры ds18b20. Один внутри помещения, второй вынесем наружу. Начнем.

В процессе изготовления самоделки нам понадобится:

Arduino UNO (Или любая другая Arduino совместимая плата)
- WG12864B графический экран
- ds18b20 датчик температуры, 2шт
- Блок питания 6 – 12 В
- Резисторы 4.7 Ком 0.25 Вт, 2 шт.
- Резисторы 100 ом 0.25 Вт
- Батарейный отсек для 4 батареек типа ААА «мизинчиковых»
- Коробка от картриджа приставки SEGA
- Изолента
- Соединительные провода
- Монтажная плата
- Кнопки
- Канцелярский нож
- Паяльник
- Припой, канифоль
- Двусторонний скотч

Шаг 1 Подготовка WG12864B3.
Тех, кто не работал до этого с экранами, может напугать большое количество модификаций, с виду одинаковых, экранов. Немного поясню. Большинство экранов такого типа работают на микросхемах ks0107/ks0108. Все экраны можно раздлить на 4 типа:

Вариант A: HDM64GS12L-4, Crystalfontz CFAG12864B, Sparkfun LCD-00710CM, NKC Electronics LCD-0022, WinStar WG12864B-TML-T

Вариант B: HDM64GS12L-5, Lumex LCM-S12864GSF, Futurlec BLUE128X64LCD, AZ Displays AGM1264F, Displaytech 64128A BC, Adafruit GLCD, DataVision DG12864-88, Topway LM12864LDW, Digitron SG12864J4, QY-12864F, TM12864L-2, 12864J-1

Вариант C: Shenzhen Jinghua Displays Co Ltd. JM12864

Вариант D: Wintek- Cascades WD-G1906G, Wintek - GEN/WD-G1906G/KS0108B, Wintek/WD-G1906G/S6B0108A, TECDIS/Y19061/HD61202, Varitronix/MGLS19264/HD61202

Выглядят они почти одинаково. Но пины подключение у них разные. Я выбрал, и вам рекомендую, WG12864B3 V2.0, но если экран пришел другой, или просто под руками такого нет, вы легко разберётесь с помощью таблицы:

Вкратце характеристики:

В интернете много разных схем подключения, и все вроде как рабочие. Все дело в том, что существуют не только разные экраны, но и два способа их подключения: последовательный и параллельный. При использовании подключения по последовательному порту – нам понадобится всего 3 выхода микроконтроллера. При параллельном минимум 13. Выбор в данном случаем очевиден, у Arduino и так не много выводов. Для параллельного соединения схема подключения следующая:

Для последовательного подключения, которое будем использовать мы, схема следующая:

WG12864B – Arduino UNO 1 (GND) - GND 2 (VCC) - +5V 4 (RS) – 10 5 (R/W) – 11 6 (E) – 13 15 (PSB) – GND 19 (BLA) – через резистор 100 Ом - +5V 20 (BLK) – GND

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

Резистор в 100 Ом нужен, чтобы напряжением в 5 вольт, случайно не сжечь диоды подсветки.

Шаг 2 Изготовление корпуса.
Для корпуса возьмем коробку от картриджа приставки Sega. Если не найдете под руками эту коробку, можно использовать и другой корпус. Главное, чтобы в него поместился экран и Arduino.

Срезаем прозрачную пленку, сверху коробки, так чтобы не оставалось кусков:

Затем, используя канцелярский нож, вырезаем окошко размером 37х69, для экрана.

С обратной стороны по краю выреза клеим двусторонний скотч, желательно черного цвета:

Снимаем защитную бумажку со скотча, и приклеиваем на него наш экран:

С внешней стороны должно выглядеть так:

Ниже экран, также на двусторонний скотч, крепим Arduino, сделав предварительно вырезы под USB- порт и гнездо питания:

Вырезы под гнезда Arduino надо делать с двух сторон коробки, так чтобы она могла свободно закрываться:

Шаг 3 Датчики температуры.
Мы будем использовать цифровые датчики температуры DS18B20. Используя их мы получаем большую точность измерения, погрешность не более 0,5 °C, в большом диапазоне температур -55 … + 125 °C. Кроме этого, датчик цифровой и все вычисления выполняет сам, а Arduino просто получает готовые показания. При подключении этого датчика не забывайте о подтягивающем резисторе, номиналом 4.7 КОм, между контактами DQ и VDD. Также возможно несколько вариантов подключения. С внешним питание, на мой взгляд лучший вариант, его и будем использовать:

При любом варианте питания, датчики подключаются параллельно:

Датчик замера температуры внутри помещения разместим на маленькой плате вместе с двумя кнопками, которые мы будем использовать для установки времени и даты часов:

Общий провод от обоих кнопок подключаем к GND, провод от первой кнопки подключаем к A0, от второй к A1.
Крепим на двусторонний скотч рядом с Arduino:

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

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

Провод от шины данных DQ обоих датчиков подключаем к pin 5 Arduino.
Vdd - +5 Arduino.
GND – GND Arduino.

Шаг 4 Питание.
Для питания можно использовать блок питания напряжением от 6 до 12 вольт. На конце провода блика питания следует напаять штекер, подходящий к гнезду питания Arduino:

Или можете поместить в корпус батарейный отсек для четырех батареек типа «ААА», «мизинчиковые». И подключить плюсовой провод от отсека к Vin Arduino, а минус к GND.

Шаг 5 Подготовка среды программировании.
Для начала необходимо скачать и установить Arduino IDE с официального сайта

А также добавить в две библиотеки, необходимые для скетча. OneWire – необходима для связи с датчиками ds18b20:

U8glib – используется для вывода информации на экран:

Скачиваем библиотеки. Затем распаковываем архивы, и перемещаем содержимое архивов в папку «libraries», находящуюся в папке с установленной Arduino IDE. Также можно добавить библиотеки через Arduino IDE. Для этого, не распаковывая архивы, запускаем Arduino IDE, выбираем в меню Скетч – Подключить библиотеку. В самом верху выпадающего списка выбираем пункт «Добавить.Zip библиотеку». Указываем место нахождения скачанных архивов. После всех действий, необходимо перезагрузить Arduino IDE.

Шаг 6 Редактирование скетча.
Датчики температуры работают по протоколу One Wire и имеют уникальный адрес для каждого устройства - 64-разрядный код. Добавлять команды поиска датчиков в скетч не целесообразно. Незачем нагружать Arduino каждый раз икать датчики. Поэтому вначале, собрав все вместе, заливаем в Arduino скетч, находящийся в меню Файл – Примеры – Dallas Temperature – OneWireSearch. Затем запускаем Инструменты - Монитор порта. Arduino должна найти наши датчики, написать адреса и показания температуры. Эти адреса необходимо записать или просто скопировать куда-нибудь. Теперь открываем скетч Ard_Tic_Tak_WG12864B_2_x_Term_Serial, и ищем строки:

Byte addr1={0x28, 0xFF, 0x75, 0x4E, 0x87, 0x16, 0x5, 0x63};//адрес внутреннего byte addr2={0x28, 0xFF, 0xDD, 0x14, 0xB4, 0x16, 0x5, 0x97};//адрес внешнего датчика

Заменяем адреса соответствующих местонахождению датчиков, на свои адреса.
У нас часы не используют модуль RTC (часы реального времени), поэтому необходимо откорректировать ход часов. Для удобства раскомментируйте строку (на экране появятся секунды):

//u8g.setPrintPos(44, 50); u8g.print(sek); // Выводим секунды для контроля правильности хода

Установите правильное время, через монитор порта. Для этого откройте монитор порта, дождитесь окончания первоначальных замеров температуры, и введите текущую дату и время в формате "день, месяц, год, часы, минуты, секунды". Без пробелов, числа разделяем запятыми или точками.

Если часы спешат, меняем значение на большее, рекомендую экспериментировать с шагом в 100 единиц. Если отстаю следует уменьшить значение в строке:

If (micros() - prevmicros >494000) { // поменять на другое для корректировки было 500000

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