Home weather station on Arduino and sending data to "People's monitoring". My homemade home weather station on Arduino Nano It's time to assemble the case

Do-it-yourself weather station.

It was in the evening, there was nothing to do after the new year. As usual, during the winter New Year holidays, I want to occupy my head and hands with something useful and creative too. During these New Year holidays I decided to make a weather station with my own hands. I started to prepare in advance, bought and assembled all the components before the new year, and did the main programming during the holidays.

(Lots of photos under the cut!)

First, I’ll go over the components, I won’t give links, since the goods on eBay (in my account) have gone to the archive. I bought many components leisurely on eBay. Tried the auction for the first time, used to always buy “buy it now”. What can I say, if you do not rush to buy, then some components can be bought cheaper (sometimes the difference is twice).

Pressure sensor BMP085
This is the main sensor. When I saw it on eBay, I realized that I wanted to build a home weather station.
The sensor arrived in an ordinary envelope, pasted over with a little bubble wrap inside.

Inside the envelope was the seller's business card and the sensor, packed in an antistatic bag and wrapped in another layer of bubble wrap

The anti-static bag was sealed so that moisture during the flight did not threaten the sensor

We get the sensor. On one side, a line of contacts was soldered, which were inserted into the foam so that they would not bend. On the other side is the sensor itself and the marking of the contacts.




Everything would be fine, but the marking of the contacts is applied in a mirror image.
The sensor is connected via the I2C bus and is powered by 3.3 V. That is, 4 wires are needed for normal operation (+, -, SDA, SCL)
You can interrogate the sensor in 2 ways: either through the library, or using the functions directly in the sketch.
Program example:

#include

#define BMP085_ADDRESS 0x77 // I2C address of BMP085

Const unsigned char OSS = 0; // Oversampling Setting

// Calibration values
int ac1;
intac2;
intac3;
unsigned int ac4;
unsigned int ac5;
unsigned int ac6;
int b1;
intb2;
intmb;
int mc;
intmd;

short temperature;
long pressure;

Void setup()
{
Serial.begin(9600);
Wire.begin();
bmp085Calibration();
}

Void loop()
{
temperature = bmp085GetTemperature(bmp085ReadUT());
pressure = bmp085GetPressure(bmp085ReadUP());
Serial.print("Temperature: ");
Serial.print(temperature/10.0, DEC);
Serial.println("C");
Serial.print("Pressure: ");
Serial.print(pressure/133.322, DEC);
Serial.println("mm Hg");
Serial.println();
delay(1000);
}

Void bmp085Calibration()
{
ac1 = bmp085ReadInt(0xAA);
ac2 = bmp085ReadInt(0xAC);
ac3 = bmp085ReadInt(0xAE);
ac4 = bmp085ReadInt(0xB0);
ac5 = bmp085ReadInt(0xB2);
ac6 = bmp085ReadInt(0xB4);
b1 = bmp085ReadInt(0xB6);
b2 = bmp085ReadInt(0xB8);
mb = bmp085ReadInt(0xBA);
mc = bmp085ReadInt(0xBC);
md = bmp085ReadInt(0xBE);
}

Short bmp085GetTemperature(unsigned int ut)
{
long x1, x2;
x1 = (((long)ut - (long)ac6)*(long)ac5) >> 15;
x2 = ((long)mc<< 11)/(x1 + md);
b5 = x1 + x2;

Return ((b5 + 8)>>4);
}

Long bmp085GetPressure(unsigned long up)
{
long x1, x2, x3, b3, b6, p;
unsigned long b4, b7;
b6 = b5 - 4000;
// Calculate B3
x1 = (b2 * (b6 * b6)>>12)>>11;
x2 = (ac2 * b6)>>11;
x3 = x1 + x2;
b3 = (((((long)ac1)*4 + x3)<>2;
// Calculate B4
x1 = (ac3 * b6)>>13;
x2 = (b1 * ((b6 * b6)>>12))>>16;
x3 = ((x1 + x2) + 2)>>2;
b4 = (ac4 * (unsigned long)(x3 + 32768))>>15;
b7 = ((unsigned long)(up - b3) * (50000>>OSS));
if (b7< 0x80000000)
p = (b7<<1)/b4;
else
p = (b7/b4)<<1;
x1 = (p>>8) * (p>>8);
x1 = (x1 * 3038)>>16;
x2 = (-7357 * p)>>16;
p += (x1 + x2 + 3791)>>4;
return p;
}

// Read 1 byte from the BMP085 at "address"
char bmp085Read(unsigned char address)
{
unsigned char data;

wire.write(address);
Wire.endTransmission();
Wire.requestFrom(BMP085_ADDRESS, 1);
while(!Wire.available())
;
return Wire.read();
}

Int bmp085ReadInt(unsigned char address)
{
unsigned char msb, lsb;
Wire.beginTransmission(BMP085_ADDRESS);
wire.write(address);
Wire.endTransmission();
Wire.requestFrom(BMP085_ADDRESS, 2);
while(Wire.available()<2)
;
msb = Wire.read();
lsb = Wire.read();
return (int) msb<<8 | lsb;
}

// Read the uncompensated temperature value
unsigned int bmp085ReadUT()
{
unsigned int ut;
// Write 0x2E into Register 0xF4
// This requests a temperature reading
Wire.beginTransmission(BMP085_ADDRESS);
Wire.write(0xF4);
Wire.write(0x2E);
Wire.endTransmission();
// Wait at least 4.5ms
delay(5);
// Read two bytes from registers 0xF6 and 0xF7
ut = bmp085ReadInt(0xF6);
return ut;
}

// Read the uncompensated pressure value
unsigned long bmp085ReadUP()
{
unsigned char msb, lsb, xlsb;
unsigned long up = 0;
// Write 0x34+(OSS<<6) into register 0xF4
// Request a pressure reading w/ oversampling setting
Wire.beginTransmission(BMP085_ADDRESS);
Wire.write(0xF4);
Wire.write(0x34 + (OSS<<6));
Wire.endTransmission();
// Wait for conversion, delay time dependent on OSS
delay(2 + (3<// Read register 0xF6 (MSB), 0xF7 (LSB), and 0xF8 (XLSB)
Wire.beginTransmission(BMP085_ADDRESS);
Wire.write(0xF6);
Wire.endTransmission();
Wire.requestFrom(BMP085_ADDRESS, 3);
// Wait for data to become available
while(Wire.available()< 3)
;
msb = Wire.read();
lsb = Wire.read();
xlsb = Wire.read();
up = (((unsigned long) msb<< 16) | ((unsigned long) lsb << 8) | (unsigned long) xlsb) >> (8-OSS);
return up;
}


In addition, the sensor has its own thermal sensor for pressure compensation and an altimeter.

Arduino Nano v3.0
This is the heart of the whole weather station. In simple terms, the controller is in miniature size.
Bought
I will not talk in detail about the controller, since this has already been done before me:


The package with lightake was prefabricated, the controller came in a package with a USB cable and an Arduino in a sealed antistatic bag.

To estimate the size, next to the Arduino put a coin with a face value of 1 ruble.

Controller board close up



The USB cable is good, with a ferrite ring. Powered by Arduino via USB cable. The development environment can be downloaded (download page). The language is “C”-like, there were no problems with mastering it, since I program a lot on it at work.

LCD screen
At work in the bins I found a compatible LCD 1602 screen. I had to tinker with the connection, since I did not find a datasheet for it. As a result, LCD earned.

But after a short operation, I noticed that this screen is not enough for me and I won’t be able to display more data, since it has only 2 lines of 16 characters each. At first it seems that these parameters are enough, but when you start programming, you understand that you can cram a maximum of 3-4 parameters. And if you make a menu (I was thinking about making a menu on this screen), then there is 1-2 free space left for parameters.
As a result, I began to look for another screen. At first I looked at the graphic screen from Nokia 3310 and even participated in the eBay auction to buy it, but it did not work out (which I am very happy about), so I had to give up this screen. Now I understand that it would be too small for my purposes, as there is something to compare with.
While browsing the shields on the Arduino by chance, I came across the 12864 graphics screen on the ST7920 controller. This screen has the right size and good resolution for my needs (128x64). That is, you can safely place 6-7 lines of 20 characters in a normally readable font. Since the screen is graphic, in addition to text in different fonts, graphics can also be placed. In short, this is exactly what I needed, everything was present in this screen, so I could not stand it and ordered.
The parcel arrived quickly and was packaged in a standard way: a bubble wrap, inside there was another layer of bubble wrap and a screen in an antistatic bag:






To estimate the size, next to the LCD put a coin with a face value of 1 ruble.




To quickly connect the screen to the Arduino, I soldered a line of contacts to the LCD pins. LCD can be connected via serial bus and parallel. I chose the first option, since there are so few free Arduino contacts.
Connection (taken from the web):

- Pin 1 (GND) connects to the common bus
- Pin 2 (VCC) is connected to the +5V power bus, and the current consumption is relatively small and the display can be powered from the built-in Arduino regulator.
- Pins 4, 5 and 6 are connected to the Arduino digital outputs, forming the SPI serial interface:
pin 4 - (RS) - corresponds to the CS line (for example 7)
pin 5 - (RW) - corresponds to the MOSI line (for example 8)
pin 6 - (E) - corresponds to the SCK line (for example 3)
Arduino pin numbers can be anything, the main thing is not to forget to correctly indicate them later in the program text when initializing the display.
- Pin 15 (PSB) is connected to the common bus.
- Pins 19 (A) and 20 (K) are backlight power supply (+5V and GND respectively). To adjust the brightness of the backlight, you can use a 10kΩ variable resistor connected between the power rails and GND. The voltage from its engine is applied to pin 19 of the display.
According to this instruction, I connected everything except the backlight. I used the Arduino PWM as the backlight power.
In order to programmatically connect the LCD to the Arduino, the u8glib library is used. You can download. If there are download problems, then I can upload the library to narod.ru.
The library itself is not complicated and allows you to display text in different fonts, draw a line, draw the simplest geometric shapes (rectangle, circle), display your images prepared in a special way. In principle, this tool is sufficient for most tasks.
Here is the result of a simple program:

The program itself:

#include "U8glib.h"

U8GLIB_ST7920_128X64 u8g(3, 9, 8, U8G_PIN_NONE); // SPI E=3, RW=9, RS=8

// Subroutine for determining free memory
int freeRam()(
extern int __heap_start, *__brkval;
intv;
return (int) &v - (__brkval == 0? (int) &__heap_start: (int) __brkval);
}

Void setup(void) (
u8g.setFont(u8g_font_6x10); // font
u8g.setRot180(); // Flip the screen
analogWrite(6, 115); // Set screen brightness (backlight anode to 6 pin)
}

Void loop(void) (
u8g.firstPage();
do(

u8g.setPrintPos(1, 12); // position
u8g.print("Hello!!!"); // text output
u8g.drawBox(0,22,128,9); // Fill The Rectangle With White
u8g.setColorIndex(0); // white ink, black background
u8g.setPrintPos(1, 30); // position
u8g.print("Word..."); // text output

U8g.setColorIndex(1); // white ink, black background
u8g.setPrintPos(1, 50); // position
u8g.print("After start ="); // text output
u8g.setPrintPos(85, 50); // position
u8g.print(millis() / 1000); // output number of seconds after start
u8g.setPrintPos(1, 64); // position
u8g.print(freeRam()); // output how much memory is used
) while(u8g.nextPage());

delay(200);
}

Real time clock DS1307
Another component for my weather station. This shield has a real time clock. I ordered them on eBay. The seller sent a watch handkerchief in an unrealistically large box


Inside the box there were two sheets of A4 with advertising and a watch handkerchief wrapped in cellophane


I want to note that the fee does not exceed the size of 2 rubles. coin, and the box was 13x15x5 cm in size.
The board was packed in an antistatic bag

Shawl up close



I had to tinker with this module. First, there were connection difficulties. And secondly, there is no quartz on this board. If I knew that I would spend so much time on the module, then most likely I would have assembled it myself, since the network is full of schemes. The simplest circuit contains 4-5 components.
Regarding the connection. I found a library that said that the I2C interface can be connected not to the usual Arduino analog inputs (A4 and A5), but to any discrete ones. Did as written. At first, nothing worked, after a long dance with a tambourine, the clock wound up. Well, I thought, that's it, the problems are over, but after I tried to connect the same module to another Arduino, the dancing with the tambourine continued. I spent a lot of time looking for a solution to this problem, and almost everywhere it was indicated either an incorrect connection or the absence of pull-up resistors on the SCL and SDA pins. I already wanted to get into the board with a soldering iron, but on one forum I accidentally stumbled upon a code where it was said that SCL and SDA should be connected to standard I2C ports on the Arduino. After the standard connection, everything immediately worked.
Now about quartz. I don’t know what kind of quartz the Chinese put there, but watches with such quartz ran 10-11 seconds a day. This error is 5 minutes per month, and 1 hour per year. You don't need a clock like this. I had to go online again and look for how to fix this bug. The first solution that came up says that you need to ground the quartz. Did it - zero result. I found somewhere else that I needed to find an old motherboard and unsolder watch quartz from there. Done - the result is. Now the clock runs away not by 10-11 seconds, but by 1.5 seconds per day. Let's just say it got better, but far from ideal. Since it is more reluctant to fiddle with a soldering iron, it was decided to adjust the clock programmatically, that is, once a day, adjust the clock to the desired value. After 10 days, the clock was gone by no more than a second. The method is good, but only when the Arduino timing device is connected to power, otherwise the clock runs on battery and still runs away.
Small test program:

#include "Wire.h"
#define DS1307_I2C_ADDRESS 0x68 // SDA A4, SCL A5

Byte decToBcd(byte val)
{
return ((val/10*16) + (val%10));
}

Byte bcdToDec(byte value)
{
return ((val/16*10) + (val%16));
}

Void setDateDs1307(byte second, // 0-59
byte minute, // 0-59
byte hour) // 0-99
{

Wire.write(0);
Wire.write(decToBcd(second));
Wire.write(decToBcd(minute));
Wire.write(decToBcd(hour));
Wire.endTransmission();
}

Void getDateDs1307(byte *second,
byte*minute,
byte*hour)
{

Wire.beginTransmission(DS1307_I2C_ADDRESS);
Wire.write(0);
Wire.endTransmission();

Wire.requestFrom(DS1307_I2C_ADDRESS, 3);

*second = bcdToDec(Wire.read());
*minute = bcdToDec(Wire.read());
*hour = bcdToDec(Wire.read());
}

Void setup()
{
byte second, minute, hour;
Wire.begin();
Serial.begin(9600);

Second = 45;
minutes = 5;
hours = 16;

SetDateDs1307(second, minute, hour);
}

Void loop()
{
byte second, minute, hour;

GetDateDs1307(&second, &minute, &hour);
Serial.print(hour, DEC);
serial print(":");
Serial.print(minute, DEC);
serial print(":");
Serial.println(second, DEC);

delay(1000);
}


The library is not used here, and the functions are truncated for reading and writing time.

Temperature and humidity sensor DHT11
There is not much to say about this sensor. I wouldn't even use it if I didn't need moisture. Unfortunately, I didn't take a picture of it when I received it, so there won't be any pictures. Photos of the sensor can be seen below, where I connected it to the Arduino. Sensor connection is simple (+, digital output, -). Typically, sensors are made with four pins. With this form factor, the third contact is not connected to anything.
To connect to the Arduino, you can use the library. You can download.
A small test program with information output to the LCD display 1602:

// include the library code:
#include
#include

// Declare objects
dht11 Dht11;
LiquidCrystal lcd(12, 11, 6, 5, 4, 3);

#define DHT11PIN 7
int i;

Void setup()
{
lcd.begin(16, 2);
lcd.print("Status: ");
i=0;
}

Void loop()
{
int chk = DHT11.read(DHT11PIN);
lcd.setCursor(8, 0);
switch (chk)
{
case 0: lcd.print("OK "); break;// lcd.setCursor(11, 0); lcd.print(millis()/2000); break;
case -1: lcd.print(“Checksum error”); merr(); break;
case -2: lcd.print("Time out error"); merr(); break;
default: lcd.print("Unknown error"); merr(); break;
}
delay(500);
lcd.setCursor(15, 0);
switch(i)
{
case 0: lcd.print("^"); lcd.setCursor(15, 1); lcd.print(" ");break;
case 1: lcd.print("v"); lcd.setCursor(15, 1); lcd.print(" ");break;
default: lcd.setCursor(15, 1); lcd.print("E"); break;
}
i=i+1;
if (i>1) i=0;
lcd.setCursor(0, 1);
lcd.print("H=");
lcd.setCursor(2, 1);
lcd.print((float)DHT11.humidity, 0);
lcd.setCursor(4, 1);
lcd print("%");
lcd.setCursor(8, 1);
lcd.print("T=");
lcd.setCursor(10, 1);
lcd.print((float)DHT11.temperature, 0);
lcd.setCursor(12, 1);
lcd.print("C");

Void mErr()
{
lcd.setCursor(2, 1);
lcd.print("**");
lcd.setCursor(10, 1);
lcd.print("**");
i=5;
}


The sensor has disadvantages - the data from the sensor comes only in integers, and the range is weak.

It seems that he wrote about all the components. It remains to collect everything into a single whole.
Oops, almost forgot! In order to assemble the device, you need a case. The case also ordered on Ebay. The seller was from England. The parcel came quickly, but I did not take a picture of it. All photos of the body are below.

First, I assembled everything on the table with the help of special wiring. I wrote a test program and uploaded it to the controller.



In fact, the blue color of the backlight is much brighter. Even at the minimum brightness (Bright=5) the frame is exposed.

To assemble everything without wires, it was decided to make a mini motherboard, and the Arduino board and shields were put on the connectors. In which case, they can be easily removed quickly. I also decided to hook the LCD screen and control buttons on the connectors, only solder the temperature sensor on the wires.
This is how the scarf came out



In the last photo, I haven’t washed off the flux yet. I glued porous rubber under the shields next to the connectors so that there was at least some kind of support. Although, in fact, the shields in the connectors on the contacts are already perfectly held.

Motherboard with shields and Arduino board installed.

This is what a complete connection to the motherboard looks like


Instead of buttons, I used a homemade shield soldered on a breadboard. As buttons I used buttons from old mice.
As you can see, the number of wires has decreased.

The main problem of placement in the case is to cut out the groove for the LCD screen evenly. No matter how hard I tried, it still didn't work out perfectly. The gaps in some places were slightly more than 1 mm. To make everything look neat, I took a black sealant for the aquarium and filled in all the cracks, at the same time I attached the screen to this particular sealant. After the sealant had dried, I cut off the excess from the outside. In bright light, the sealant is visible, and in normal light, everything merges with the case.
This is what the case looks like from the inside with the LCD screen and the motherboard installed.

This is what it looks like from the outside in bright light (I apologize for the fingerprints, I saw them when I was sorting out the photos).

I thought for a long time how to attach the buttons to the case and, most importantly, which buttons to use ...
In electronic stores, I liked the button with a long pin and the tips that are put on this pin. These buttons are used for soldering to the board. Everything would be fine, but they have a minus - the pressing stroke is very small and loud.
I had to place the buttons in two stages: the first was to place the buttons on the board, the second was to mount this board on another board. And then put all this into the body on the guides.

This is how the scarf with buttons looks like:



This is what the board looks like:


Here you can see the guides into which the board with the buttons is inserted. I soldered some elements in order to stiffen the board.

Now we put everything in the body
Without connecting buttons:


With button connection:

Close the box and turn it on. Everything works fine, the buttons work as they should.

At the end I post a short video of the device in different modes:
http://www.youtube.com/watch?v=KsiVaUWkXNA&feature=youtu.be
For those who don't see the video here, here's the link to

It's time to end the review.
I will write a little about the program, and then brief conclusions. When I wrote the program, I did not think that I would run into a limit of 30720 bytes very quickly.


I had to optimize the code. Moved many pieces of code into subroutines. I would never have thought that a switch ... case statement in a compiled form takes up more space than several if ... else. The correct declaration of variables also saves space. If you declare an array long, although it is quite possible to get by with byte, then the memory overrun reaches 500 bytes, depending on the size of the array. When you write a program, you don’t think about it, and only later, when you analyze the program, you realize that you did some things wrong, and you start optimizing the code. After the problems with the size of the program were resolved, I ran into a limitation of RAM. This was expressed in the fact that the program began to hang after loading. I had to enter a subroutine for calculating free RAM. As a result, I was forced to abandon one weather prediction algorithm, since it must display icons on the screen. The algorithm itself works, but the output of the icons had to be reserved. I still have ideas on how to optimize the code, but in the near future I will leave the device working as it is in order to evaluate performance and identify all bugs.

Now some conclusions
Minuses
1) Price. The excuse for this minus is that a hobby is never cheap.

pros
1) Great functionality of the device
2) Function expansion is limited only by the controller used and your own desire
3) Aesthetic pleasure from contemplation and moral satisfaction from the fact that I nevertheless assembled and completed this device

I plan to buy +86 Add to favorites Liked the review +137 +304

In this article, we will talk about how to assemble a full-fledged weather station that transmits weather data to the well-known “people's monitoring” service.

Our weather station will consist of two devices: a compact autonomous device that measures weather indicators, and a repeater device that receives these indicators and sends them to “people's monitoring”. The devices will communicate via a wireless communication channel at a frequency of 433 MHz. The autonomous part will be powered by three AA batteries and will be able to operate on one set of batteries for up to a year with a sensor polling period of 20 minutes.

This design allows you not to drill walls for laying wires from the street, where it is necessary to make measurements, to the room where the results of these measurements must be used.

What does that require?

To make a standalone transmitter, we need:

    x3 AA AA battery holder

To make a repeater, we need:

It is also convenient to install two LEDs to indicate processes:

For sound indication of the battery discharge of the autonomous part, it is convenient to use a piezo tweeter:

How to assemble it?

Assembling a standalone part

Repeater Assembly

This completes the assembly of the minimally functional repeater. If you want to install LED indication and sound alarm, please follow the steps below.


Source

Offline part code

meteo_sensor.ino #include #include #include #include // Timeout between sendings (no more than 65535)#define TIMEOUT 60000 // Number of attempts to send a package#define ATTEMPTS 3 // Transmitter information pin#define RF_PIN 5 // Temperature and humidity sensor pins#define GND1_PIN 10 #define VCC1_PIN 11 #define GND2_PIN 7 #define VCC2_PIN 8 #define DATA_PIN 12 #define CLK_PIN 9 AmperkaLine rf(RF_PIN) ; SHT1x sht1x(CLK_PIN, DATA_PIN) ; void loop(void) ; // Function to put the board to sleep. Every TIMEOUT seconds // loop_func will be called. TEENSY3_LP LP = TEENSY3_LP() ; sleep_block_t* LP_config; void sleep_mode(void ) ( LP_config = (sleep_block_t* ) calloc (1 ,sizeof (sleep_block_t) ) ; // We will wake up on a timer LP_config->modules=(LPTMR_WAKE) ; // Set the timeout for the timer LP_config->lptmr_timeout=TIMEOUT; // After the timeout, the loop function will be called LP_config->callback=loop; LP.Hibernate(LP_config) ; ) // Peripheral enable function void peripheral_start(void ) ( // Turn on the data line pinMode(RF_PIN, OUTPUT) ; // Turn on the power and ground of the temperature and humidity sensors pinMode(GND1_PIN, OUTPUT) ; pinMode(GND2_PIN, OUTPUT) ; pinMode(VCC1_PIN, OUTPUT) ; pinMode(VCC2_PIN, OUTPUT) ; digitalWrite(GND1_PIN, LOW) ; digitalWrite(GND2_PIN, LOW) ; digitalWrite(VCC1_PIN, HIGH) ; digitalWrite(VCC2_PIN, HIGH) ; // Turn on the LED to indicate transmission pinMode(LED_BUILTIN, OUTPUT) ; digitalWrite(LED_BUILTIN, HIGH) ; // Select the internal voltage as the reference voltage// source (=1.2V) analogReference(INTERNAL) ; ) // Peripheral shutdown function void peripheral_stop(void ) ( // Turn off the data line pinMode(RF_PIN, INPUT) ; // Turn off the temperature and humidity sensor pinMode(GND1_PIN, INPUT) ; pinMode(GND2_PIN, INPUT) ; pinMode(VCC1_PIN, INPUT) ; pinMode(VCC2_PIN, INPUT) ; pinMode(18 , INPUT_PULLUP) ; pinMode(19 , INPUT_PULLUP) ; // Turn off the LED digitalWrite(LED_BUILTIN, LOW) ; ) void setup(void ) ( // We don't initialize anything, we immediately fall asleep sleep_mode() ; ) // This function is executed once every TIMEOUT seconds void loop(void ) ( unsigned long msg; byte temp, humidity, voltage; // Turn on peripherals peripheral_start() ; // Wait for the temperature and humidity sensor to turn on delay(30) ; // Get input from sensors temp = (byte) (sht1x.readTemperatureC () + 40 .) * 2 ; humidity = (byte) sht1x.readHumidity () ; voltage = analogRead(A0) / 4 ; // Compose a package from the data msg = 0 ; msg | = voltage; msg<<= 8 ; msg | = humidity; msg <<= 8 ; msg | = temp; // Send a package several times for (int i = 0 ; i< ATTEMPTS; i++ ) rf.send (msg) ; // Turn off peripherals peripheral_stop() ; // After exiting the function, the board will fall asleep again }

Indoor board code

receiver.ino #include #include #include #include byte mac = ( 0x90 , 0xA7 , 0xDA , 0x0F , 0xBC , 0x75 ) ; charserver = "narodmon.com" ; EthernetClient client; const int rfpin = 7 ; AmperkaLine rf(rfpin) ; void setup(void ) ( pinMode(rfpin, INPUT) ; pinMode(6 , OUTPUT) ; Serial.begin (9600 ) ; Serial.println ("Started." ) ; ) void loop(void ) ( static unsigned long pushtimeout = 0 ; static float temp, humidity, voltage; unsigned long msg; int res; if ((res = rf.receive (& msg) ) == 0 ) ( temp = ((float ) (msg& 0xFF ) ) / 2 . - 40 .; msg >>= 8 ; humidity = (float ) (msg& 0xFF ) ; msg >>= 8 ; voltage = (float ) (msg& 0xFF ) / 256 . * 1.2 * 10 * 1.1 ; digitalWrite(6 , HIGH) ; Serial.print ("Temp: " ) ; Serial.print (temp) ; Serial.print (", humidity: " ) ; Serial.print (humidity) ; Serial.print (", voltage: " ) ; Serial.println ( voltage) ; digitalWrite(6 , LOW) ; ) else Serial.println ("E" ) ; if (millis() - pushtimeout > 60000 * 5 ) ( pushtimeout = millis() ; Serial.println ("Starting Ethernet... " ) ; if (Ethernet.begin (mac) == 0 ) ( Serial.println ( "Failed to configure Ethernet using DHCP") ; while (1 ) ( ) ) delay(1000 ) ; Serial.println("connecting..." ) ; if (client.connect (server, 8283 ) ) ( Serial.println ("connected" ) ; client.println ( "#90-A7-DA-0F-BC-75#Sensor#55.751775#37.616856#0.0") ; client.print("#90A7DA0FBC7501#" ) ; client.print (temp, DEC) ; client.println("#In") ; client.print("#90A7DA0FBC7502#" ) ; client.print(humidity, DEC) ; client.println("#Humidity"); client.print("#90A7DA0FBC7503#" ); client.print (voltage, DEC) ; client.println("#Voltage"); client.println("##"); ) else Serial.println("connection failed" ) ; ( unsigned long tm = millis() ; while (millis() - tm< 5000 ) { if (client.available () ) { char c = client.read () ; Serial.print (c) ; } } } client.stop () ; } }

Registration of a weather station in the "People's Monitoring"

In order for the data transmitted by our device to be correctly displayed on public monitoring, you must do the following:


Demonstration of the device

What else can be done?

    Teensy has a real time clock (RTC) on board. For their performance, only quartz is not enough. You can buy quartz at 32.768 kHz at any radio element store and solder it. Then you can wake up Teensy with an RTC alarm. The advantage is that you can wake up the device more often during those hours when more accurate readings are needed. For example, during working hours, wake up the device every 5 minutes, and the rest - every half an hour.

In my free time, and this time I wrote instructions for making a small weather station. It will function as a clock with a date and show the temperatures inside and outside the room. We will use an Arduino UNO as the main controller, but another board with an Atmega328p on board will do. For display, we use the WG12864B graphic screen. We will also connect two ds18b20 temperature sensors. One is indoors, the other is taken outside. Let's start.

In the process of making homemade products, we need:

Arduino UNO (Or any other Arduino compatible board)
- WG12864B graphic screen
- ds18b20 temperature sensor, 2 pcs
- Power supply 6 - 12 V
- Resistors 4.7 Kom 0.25 W, 2 pcs.
- Resistors 100 ohm 0.25 W
- Battery compartment for 4 AAA "little finger" batteries
- Box from the SEGA console cartridge
- Insulating tape
- Connecting wires
- Circuit board
- Buttons
- Stationery knife
- soldering iron
- Solder, rosin
- Double sided tape

Step 1 Prepare WG12864B3.
Those who have not worked with screens before may be intimidated by the large number of modifications to seemingly identical screens. I'll explain a little. Most screens of this type work on ks0107/ks0108 chips. All screens can be divided into 4 types:

Option A: HDM64GS12L-4, Crystalfontz CFAG12864B, Sparkfun LCD-00710CM, NKC Electronics LCD-0022, WinStar WG12864B-TML-T

Option B: HDM64GS12L-5, Lumex LCM-S12864GSF, Futurlec BLUE128X64LCD, AZ Displays AGM1264F, Displaytech 64128A BC, Adafruit GLCD, DataVision DG12864-88, Topway LM12864LDW, Digitron SG12864J4, QY-1286 4F, TM12864L-2, 12864J-1

Option C: Shenzhen Jinghua Displays Co Ltd. JM12864

Option D: Wintek- Cascades WD-G1906G, Wintek - GEN/WD-G1906G/KS0108B, Wintek/WD-G1906G/S6B0108A, TECDIS/Y19061/HD61202, Varitronix/MGLS19264/HD61202

They look almost the same. But the connection pins are different. I chose, and I recommend to you, WG12864B3 V2.0, but if the screen came in a different one, or you just don’t have it at hand, you can easily figure it out using the table:

Brief specifications:

There are many different connection schemes on the Internet, and everything seems to work. The thing is that there are not only different screens, but also two ways to connect them: serial and parallel. When using a serial port connection, we need only 3 microcontroller outputs. With a parallel minimum of 13. The choice in this case is obvious, the Arduino does not have many conclusions anyway. For parallel connection, the connection diagram is as follows:

For a serial connection, which we will use, the scheme is as follows:

WG12864B - Arduino UNO 1 (GND) - GND 2 (VCC) - +5V 4 (RS) - 10 5 (R/W) - 11 6 (E) - 13 15 (PSB) - GND 19 (BLA) - via resistor 100 Ohm - +5V 20 (BLK) - GND

To adjust the contrast, a potentiometer must be on the screen. There are screens without it, but this is now rare:

A 100 ohm resistor is needed so that a voltage of 5 volts does not accidentally burn the backlight diodes.

Step 2 Making the case.
For the case, take the box from the cartridge of the Sega set-top box. If you do not find this box at hand, you can use another case. The main thing is that the screen and Arduino fit in it.

Cut off the transparent film, on top of the box, so that there are no pieces left:

Then, using a clerical knife, cut out a 37x69 window for the screen.

On the reverse side, along the edge of the cutout, we glue double-sided tape, preferably black:

We remove the protective paper from the adhesive tape, and glue our screen on it:

From the outside it should look like this:

Below the screen, also on double-sided tape, we mount the Arduino, having previously made cutouts for the USB port and the power socket:

Cutouts for the Arduino sockets must be made on both sides of the box so that it can close freely:

Step 3 Temperature sensors.
We will use DS18B20 digital temperature sensors. Using them, we obtain greater measurement accuracy, an error of not more than 0.5 °C, in a wide temperature range of -55 ... + 125 °C. In addition, the sensor is digital and performs all the calculations itself, and the Arduino simply receives ready-made readings. When connecting this sensor, do not forget about the 4.7KΩ pull-up resistor between the DQ and VDD pins. Several connection options are also possible. With external power, in my opinion the best option, we will use it:

With any power supply, the sensors are connected in parallel:

We will place the indoor temperature sensor on a small board along with two buttons that we will use to set the time and date of the clock:

We connect the common wire from both buttons to GND, connect the wire from the first button to A0, from the second to A1.
We fix it on double-sided tape next to the Arduino:

The sensor, which is supposed to be placed outside the room, is better to choose in a metal, dust-proof housing:

Calculate the wire of the required length so that you can hang the sensor outside the window, the main thing is that it should not be more than 5 meters, if you need a longer length, you will need to reduce the value of the pull-up resistor.

We connect the wire from the DQ data bus of both sensors to pin 5 of the Arduino.
Vdd - +5 Arduino.
GND - GND Arduino.

Step 4 Nutrition.
For power, you can use a power supply with a voltage of 6 to 12 volts. At the end of the power flare wire, solder a plug that fits the Arduino power socket:

Or you can put a battery compartment for four "AAA", "little finger" batteries into the case. And connect the positive wire from the bay to Vin Arduino, and the negative wire to GND.

Step 5 Prepare the programming environment.
First you need to download and install the Arduino IDE from the official website

And also add to the two libraries needed for the sketch. OneWire - required for communication with ds18b20 sensors:

U8glib - used to display information on the screen:

Downloading libraries. Then we unpack the archives, and move the contents of the archives to the "libraries" folder, located in the folder with the installed Arduino IDE. You can also add libraries through the Arduino IDE. To do this, without unpacking the archives, run the Arduino IDE, select Sketch - Connect Library from the menu. At the very top of the drop-down list, select the "Add. Zip Library" item. Specify the location of the downloaded archives. After all the steps, you need to restart the Arduino IDE.

Step 6 Editing the sketch.
Temperature sensors work using the One Wire protocol and have a unique address for each device - a 64-bit code. It is not advisable to add commands to search for sensors in the sketch. There is no need to load the Arduino every time to hiccup sensors. Therefore, first, having collected everything together, we fill in the Arduino sketch, located in the menu File - Examples - Dallas Temperature - OneWireSearch. Then we launch Tools - Port Monitor. Arduino should find our sensors, write addresses and temperature readings. These addresses must be written down or simply copied somewhere. Now open the Ard_Tic_Tak_WG12864B_2_x_Term_Serial sketch and look for the lines:

Byte addr1=(0x28, 0xFF, 0x75, 0x4E, 0x87, 0x16, 0x5, 0x63);// address of internal byte addr2=(0x28, 0xFF, 0xDD, 0x14, 0xB4, 0x16, 0x5, 0x97); sensor

We replace the addresses of the sensors corresponding to the location with our addresses.
Our clock does not use the RTC module (real time clock), so it is necessary to correct the clock. For convenience, uncomment the line (seconds will appear on the screen):

//u8g.setPrintPos(44, 50); u8g.print(sec); // Output seconds to control the correctness of the move

Set the correct time using the port monitor. To do this, open the port monitor, wait for the initial temperature measurements to finish, and enter the current date and time in the format "day, month, year, hours, minutes, seconds". No spaces, numbers are separated by commas or dots.

If the clock is in a hurry, change the value to a larger one, I recommend experimenting with a step of 100 units. If lagging behind should decrease the value in the line:

If (micros() - prevmicros >494000) ( // change to something else to adjust it was 500000

Empirically, we determine the number at which the clock runs accurately enough. To determine the accuracy of the move, you need the output of seconds. After precise calibration of the number, seconds can be commented out and thus removed from the screen.
Uploading the sketch.

The project of the weather station was taken as a basis from the book by V. Petin "Projects using the Arduino controller" 2nd edition (project 5 of appendix 2). Used Arduino IDE 1.8.5 on Windows 10.
An error was thrown when running the sketch

On the Internet, you can download libraries for Arduino that have the same name, but different content. The sketch may not work if you are using the "wrong" library. Apparently, I got the wrong libraries. I added a BMP180 sensor to the project to measure atmospheric pressure and reworked the sketch.

Connection diagram

Scanning addresses

First, connect the BMP180 sensor and the LCD1602 indicator to the Arduino. Compile the I2C scanner sketch and run it to determine the device addresses on the I2C bus.

Every 5 seconds, the program scans devices and issues addresses to the COM port. I have found two devices with addresses 0x3F and 0x77. BMP180 has address 0x77 by default, so LCD indicator has address 0x3F.
In some of the schematics, the books are mixed up where the SDA and SCL signals are connected to the Arduino board. Should be: SDA - to A4, SCL - to A5. If the BMP180 module has five pins, then +5 volts is applied to the VIN pin.

Wiring diagram

Now assemble the circuit completely. I used a common cathode RGB LED mounted on a board along with 150 ohm resistors. The common cathode is connected to the GND pin, the other pins are connected according to the diagram. There is no need to make changes to the sketch, since the brightness of the LEDs changes according to a cyclic law.
The diagram shows the connection of an RGB LED with a common anode, as in the book.
If no characters are visible on the LCD1602 screen, turn the brightness control. The backlight of the indicator consumes quite a lot of current, so use a power supply with a current of at least 2 A. I used a USB hub with an external 2 A power supply.
In the circuit, I used a ZP-22 piezo call. The resistor connected to the bell is 100 ohms. The sound frequency can be changed in the program. I chose a frequency of 1000 Hz. If you come across a buzzer with a fixed sound frequency, then you can turn it on and off simply by applying and removing voltage, like a regular LED. When the sketch starts, a short beep sounds. You can enable periodic signaling while the program is running by uncommenting the line //bzz(100); in a sketch.
In the project, I used a DHT11 sensor in the form of a module with a 4.7 kΩ resistor already mounted. Resistance can be from 4.7 to 10 kOhm.
Connect the Vcc pin of the DS1302 clock module to the +5 Volt rail. This way you will reduce the battery drain, in fact it will only work when the power to the Arduino is turned off.

Program (sketch)

The bmp085 library was used to serve the BMP180. The pressure value depends on the height of the terrain. For the correct value of atmospheric pressure, you need to choose the height. To do this, edit the line dps.init(MODE_STANDARD, 10000, true); My height is 100 m (10000 cm). The pressure calculation fragment is taken from the example BMP085_test2.ino of the bmp085 library.

meteo_P sketch

#include
#include
#include
#include "dht.h"
#include
BMP085 dps = BMP085();
long Pressure = 0, Altitude = 0;
unsigned long time1 = 0;

#define DHTPIN 10
#define DHTTYPE 11 // 11 - DHT11, 22 - DHT22
DHT dht(DHTPIN, DHTTYPE);

int kCePin = 4; // RST DS1302
int kIoPin = 3; // Data DS1302
int kSclkPin = 2; // CLK DS1302
DS1302 rtc(kCePin, kIoPin, kSclkPin);

int REDpin = 9;
int GREEN pin = 6;
int BLUE pin = 11;

LiquidCrystal_I2C lcd(0x3f, 16, 2); // set your address 0x20...0xff address
unsigned long memTime;
int bzzPin = 8;

void HumTempRead() (
float hum = dht.readHumidity();
float temp = dht.readTemperature();
if (isnan(hum) || isnan(temp)) (
Serial.println("Failed to read from DHT sensor!");
lcd.setCursor(0, 1);
lcd.print("H=--% T=---");
lcd.setCursor(11, 1);
lcd.print((char)223);
lcd.setCursor(12, 1);
lcd.print("C");
) else (
lcd.setCursor(0, 1);
lcd.print("H=");
lcd.setCursor(2, 1);
lcd print(hum);
lcd.setCursor(4, 1);
lcd.print("%T=+");
lcd.setCursor(9, 1);
lcd print(temp);
lcd.setCursor(11, 1);
lcd.print((char)223);
lcd.setCursor(12, 1);
lcd.print("C") ;
}
}

void setup_bzz() (
pinMode(bzzPin, OUTPUT);
}

void bzz(int _bzzTime) (
tone(bzzPin, 1000 , _bzzTime); // frequency 1000 Hz
}

void setup()(
Serial.begin(9600);
Wire.begin();
delay(1000);

dps.init(MODE_STANDARD, 10000, true); // 100 meters (altitude in cm)

dht.begin();
setup_bzz();
bzz(100);

lcd.init();
lcd.backlight();
lcd.home();
// lcd.setCursor(0, 0);

rtc.halt(false);
rtc.writeProtect(false);

//rtc.setDOW(FRIDAY); // Set Day-of-Week to FRIDAY set the day of the week
//rtc.setTime(4, 58, 0); // Set the time to 12:00:00 (24hr format)
//rtc.setDate(6, 8, 2010); // Set the date to August 6th, 2010 set the date (day, month, year)
}

lcd.setCursor(8, 0);
lcd.print(rtc.getTimeStr());

if ((millis() - memTime > 2000) or (millis()< memTime)) { // DHT11/22 1 time each 2 seconds
HumTempRead();
memTime = millis();
}
delay(100);

if (((millis() - time1) / 1000.0) >= 1.0) (
dps.calcTrueTemperature();
time1 = millis();
}
dps.getPressure(&Pressure);
Serial.print("Pressure(Pa):");
Serial println(Pressure);

longp2;
intpi;
p2 = (Pressure / 133.3224); // Pa in mmHg
pi = trunc(p2); // discarding the fractional part of the number

lcd.setCursor(0, 0);
lcd.print("P=");
lcd.setCursor(2, 0);
lcd print(pi); // output atm. pressure on LCD
lcd.setCursor(5, 0);
lcd.print("mm");
// delay(3000);
//bzz(100); // uncomment if you want to listen for signals
{
for (int value = 0 ; value<= 255; value += 1) {
analogWrite(REDpin, value);
analogWrite(GREENpin, 255 - value);
analogWrite(BLUEpin, 255);
delay(5);
}

for (int value = 0; value<= 255; value += 1) {
analogWrite(REDpin, 255);
analogWrite(GREENpin, value);
analogWrite(BLUEpin, 255 - value);
delay(5);
}

for (int value = 0; value<= 255; value += 1) {
analogWrite(REDpin, 255 - value);
analogWrite(GREENpin, 255);
analogWrite(BLUEpin, value);
delay(5);
}
}
}

In the File Catalog you can download the sketch and libraries that were used in the project.

Import the LiquidCrystal_I2C.zip, bmp085.zip, DS1302.zip and DHT.zip libraries from the downloaded archive into the Arduino IDE. Go to the menu Sketch Connect library Add .zip library... and in the window select the library zip archive.
Download the meteo_P sketch. Replace the LCD1602 address in the sketch with the value obtained from the scan of the I2C bus. Compile and run the sketch.
If the sketch works, then open the port monitor and view the output messages. Pick up the height in the statement dps.init(MODE_STANDARD, 10000 , true); to get real pressure values.
Set your clock. Uncomment the line //rtc.setTime(4, 58, 0); and in brackets specify the current time (hour, minutes and seconds separated by commas) and reload the sketch into the controller. After the time is set, comment out this line again and restart the sketch again.
If the illumination of the night light annoys you, you can tweak it by changing the length of the delay in the for loops at the end of the sketch. With delay(2); loop lasts 2-3 seconds, with delay(5); — from 4 to 5 seconds, with delay(30); - up to 15-16 seconds. The information on the indicator will be updated at the same interval.
When using the weather station autonomously, i.e. without connecting to the USB port of the computer, comment out the lines with the words Serial ... in the sketch to disable the output of information to the COM port monitor.

PS. In the sketch of the book and in the examples for the DHT library, the definition line is indicated #define DHTTYPE DHT 11. The sketch runs but crashes after a few hours. The clock stops, the display does not change. An indistinct message appears in the port monitor, in which there is a reference to dht.
In this line, I removed the letters DHT, i.e. did #define DHTTYPE 11. After that, the sketch began to work stably.

Article updated 06/25/2018

Used resources
1. Petin V.A. Projects using the Arduino controller (Electronics) 2nd edition, St. Petersburg. BHV-Petersburg, 2015 464 p.
2. Petin V. A., Binyakovsky A. A. Practical Arduino Encyclopedia. - M., DMK Press, 2017. - 152 p.
3.http://arduinolearning.com/code/i2c-scanner.php
4. http://arduino.ru/forum/programmirovanie/ds1302lcd1602
5. http://robotics18.rf/how-to-connect-lcd-1602-to-arduino-by-i2c/
6. BMP085_test2.ino example from bmp085.zip library
7. http://proginfo.ru/round/
8. http://homes-smart.ru/index.php?id=14&Itemid=149&option=com_content&view=article
9. http://iarduino.ru/lib/datasheet%20bmp180.pdf
10. http://it-donnet.ru/hd44780_dht11_arduino/

It is advisable to download the firmware before connecting the components to make sure that the board is working. After assembly, you can flash again, the board should calmly flash. In projects with high power consumers in the board's 5V power circuit (addressable LED strip, servos, motors, etc.), it is necessary to apply external 5V power to the circuit before connecting the Arduino to the computer, because USB will not provide the necessary current if, for example, the strip requires it. This can burn out the protection diode on the Arduino board. A guide for downloading and uploading the firmware can be found under the spoiler on the next line.

The contents of folders in the archive

  • libraries– project libraries. Replace existing versions
  • firmware- Firmware for Arduino
  • schemes– component connection diagrams

Additionally

  • As the experiment showed, outside the case the temperature sensor shows 0.5 degrees less than inside! It is necessary to more successfully arrange electronics, remove and shield heat from heating elements ...

  • If the display is too dim/white
    On the display driver board (to which the wires are connected) there is a contrast knob, with its help you can adjust the contrast to the desired one. Also, the contrast depends on the angle of view of the display (this is LCD) and you can adjust the display for a clear display even at an angle “the display is at the level of the navel, we look from above”. And the contrast strongly depends on the power supply: from 5V, the display shows as clearly and brightly as possible, while when powered from USB via Arduino, the voltage will be about 4.5V (part of it falls on the protective diode along the USB line), and the display shows not so bright. Adjust the output with a knob with an external power supply from 5V!

  • If the CO2 sensor does not work correctly (infa from Evgeny Ivanov)
    Well, there are sketches for calibration in the sensor library folder in examples. it can also be started dumb by shorting the “HD” connector to ground for 7+ seconds.
    Of course, right on the street in the cold, it’s not necessary to do this ... you can just fill the bottle with fresh air with a sensor inside and seal it. calibration takes at least 20 minutes.
    By default, the sensor is supplied with auto-calibration enabled, which occurs every day, and if the sensor is used in an unventilated room, then this calibration quickly takes the values ​​from the norm beyond the horizon, so it must be disabled.
    Documentation.

  • Sensor auto-calibration CO2 is disabled in the sketch!

  • If you have BME280 sensor not working, most likely it has a different address. The project uses the Adafruit_BME280 library, which does not have a separate address change function, so the address is set manually in the Adafruit_BME280.h library file almost at the very beginning of the file ( is in the Adafruit_BME280 folder in your libraries folder, you should have installed it there), my module had address 0x76. How can I find out the address of my BME280 module? There is a special sketch called i2c scanner. You can google it, you can. Flash this sketch, open the port and get a list of addresses of devices connected to the i2c bus. So that the other modules do not bother you, you can turn them off and leave only the BME280. We specify the received address in the library, save the file and load the weather clock firmware. All!

  • If the clock is behind, the problem is most likely in the power circuit. If the problem persists when changing the power supply to a better one, hang a capacitor to power the RTC module (solder directly on the board to VCC and GND): be sure to be ceramic, 0.1-1 uF (marking 103 or 104, see the marking table). You can also put an electrolyte (6.3V, 47-100 uF)

Firmware settings

#define RESET_CLOCK 0 // reset the clock while the firmware is being loaded (for a module with a non-removable battery). Do not forget to put 0 and flash again! #define SENS_TIME 30000 // update time of sensor readings on the screen, milliseconds #define LED_MODE 0 // RGB LED type: 0 - main cathode, 1 - main anode #define LED_BRIGHT 255 // CO2 LED brightness (0 - 255) #define BLUE_YELLOW 1 // yellow color instead of blue (1 yes, 0 no) but due to connection features yellow is not so bright #define DISP_MODE 1 // display in the upper right corner: 0 - year, 1 - day of the week, 2 - seconds #define WEEK_LANG 1 // language of the day of the week: 0 - English, 1 - Russian (transliterated) #define DEBUG 0 // display the sensor initialization log at startup #define PRESSURE 1 // 0 - pressure graph, 1 - rain forecast graph (instead of pressure ). Don't forget to fix chart limits // display limits for graphs #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

Liked the article? Share with friends: