📜 ⬆️ ⬇️

Mobile weather station at Arduino

Probably everyone who begins his acquaintance with the Arduino, blinking the LED and connecting a button, proceeds to create his own meteorological station. I am no exception.

After reviewing various projects on the Internet, certain requirements were made. The device should display the time, temperature, pressure and schedule of its change. I also wanted to calculate the phases of the moon and the time of sunrise and sunset. And the most important requirement was mobility. The portable weather station being created was supposed to be used as an aid for fishing, so it had to be compact in size and have a certain autonomy.

Creating a case for any homemade is quite a challenge. A Motorola T192 mobile phone was found in the bins.

image
')
It turned out that the screen from Nokia 3310 becomes excellent in it (of course, it would be more convenient to use the Nokia 3310 itself).
Manage everything was assigned to the Arduino Pro Mini.

image

In order not to fail the buttons, a breadboard was inserted. When glueing the keyboard, it was noticed that the pitch of the holes of the breadboard almost coincided with the buttons. In the future, this allowed the use of buttons.

image

To measure the pressure applied sensor bmp180. The ds1302 module was taken as a clock, but to save space, only a microcircuit was taken from it. Quartz was dropped from the motherboard, and the battery was removed from the laptop (of course, you can also use the regular cr2032 in a thermocommetric).

image

Since there were free exits, the display backlight was hung on one of the free and the button on the second.

image

A Li-ion charge module on the TP4056 was used to charge the lithium battery.

image

The final view of the device (wires sticking to the right are for firmware, so they will be removed soon.)

image

When writing a program using conventional tools. The only thing I would like to draw attention to the library TimeLord.h (https://github.com/probonopd/TimeLord). With the help of its functions, specifying the date, coordinates and time zone, you can determine the time of rising and setting of the sun, the phase of the moon. Description can be downloaded at the link: TimeLord.pdf .

With regards to battery life, a short test showed that the device will work for a week exactly. This result is quite satisfactory, so further experiments on energy saving have been postponed.

The sketch currently uses 81% of the device's memory, so it is possible to add something else.

image

An antenna is displayed on the screen (signal strength indicator). This is a reserve for testing the radio module at 433 MHz, for obtaining the true temperature and humidity from an external module.

Source code
#include <BMP085.h> #include <EEPROM.h> #include <Adafruit_GFX.h> #include <Adafruit_PCD8544.h> #include <DS1302.h> #include <TimeLord.h> #include <Wire.h> //84x48 Adafruit_PCD8544 display = Adafruit_PCD8544(3, 4, 5, 6, 7); // Create a DS1302 object. DS1302 rtc(12, 11, 10);// Chip Enable, Input/Output, Serial Clock Time t = rtc.time(); String dayAsString(const Time::Day day) { switch (day) { case Time::kSunday: return "Sunday"; case Time::kMonday: return "Monday"; case Time::kTuesday: return "Tuesday"; case Time::kWednesday: return "Wednesday"; case Time::kThursday: return "Thursday"; case Time::kFriday: return "Friday"; case Time::kSaturday: return "Saturday"; } return "(unknown day)"; } //------------- TimeLord tardis; float const LATITUDE = 52.70; float const LONGITUDE = 25.40; //byte today[] = {0,0,12,22,03,16}; byte today[6]; //------------- //long previousMillis = 0, previousMillis2 = 0; //     //long interval = 1800000; //    //long interval = 3600000; //    //long interval2 = 1000; //    byte prevSecond = 99, prevHour = 99; //------------- BMP085 dps = BMP085(); long Temperature = 0, Pressure = 0; float t_f = 0; //-------------buttons-------------------- int buttonPushCounter = 0; int buttonState = 0; int lastButtonState = 0; //-------------moon---------------------- //0.0 New Moon 0.99 - Almost new const unsigned char PROGMEM moon0[] = { B00000111, B11100000, B00001000, B00010000, B00010000, B00001000, B00100000, B00000100, B01000000, B00000010, B10000000, B00000001, B10000000, B00000001, B10000000, B00000001, B10000000, B00000001, B10000000, B00000001, B01000000, B00000010, B00100000, B00000100, B00010000, B00001000, B00001000, B00010000, B00000111, B11100000 }; //Waxing Crescent const unsigned char PROGMEM moon1[] = { B00000111, B11100000, B00001000, B01110000, B00010000, B00111000, B00100000, B00011100, B01000000, B00001110, B10000000, B00001111, B10000000, B00001111, B10000000, B00001111, B10000000, B00001111, B10000000, B00001111, B01000000, B00001110, B00100000, B00011100, B00010000, B00111000, B00001000, B01110000, B00000111, B11100000 }; //0.25 First Quarter const unsigned char PROGMEM moon2[] = { B00000111, B11100000, B00001000, B11110000, B00010000, B11111000, B00100000, B11111100, B01000000, B11111110, B10000000, B11111111, B10000000, B11111111, B10000000, B11111111, B10000000, B11111111, B10000000, B11111111, B01000000, B11111110, B00100000, B11111100, B00010000, B11111000, B00001000, B11110000, B00000111, B11100000 }; //Waxing Gibbous const unsigned char PROGMEM moon3[] = { B00000111, B11100000, B00001011, B11110000, B00010111, B11111000, B00101111, B11111100, B01001111, B11111110, B10001111, B11111111, B10001111, B11111111, B10001111, B11111111, B10001111, B11111111, B10001111, B11111111, B01001111, B11111110, B00101111, B11111100, B00010111, B11111000, B00001011, B11110000, B00000111, B11100000 }; //0.5 Full Moon const unsigned char PROGMEM moon4[] = { B00000111, B11100000, B00001111, B11110000, B00011111, B11111000, B00111111, B11111100, B01111111, B11111110, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B01111111, B11111110, B00111111, B11111100, B00011111, B11111000, B00001111, B11110000, B00000111, B11100000 }; //Waning Gibbous const unsigned char PROGMEM moon5[] = { B00000111, B11100000, B00001111, B11010000, B00011111, B11101000, B00111111, B11110100, B01111111, B11110010, B11111111, B11110001, B11111111, B11110001, B11111111, B11110001, B11111111, B11110001, B11111111, B11110001, B01111111, B11110010, B00111111, B11110100, B00011111, B11101000, B00001111, B11010000, B00000111, B11100000 }; //0.75 Third Quarter (Last Quarter) const unsigned char PROGMEM moon6[] = { B00000111, B11100000, B00001111, B00010000, B00011111, B00001000, B00111111, B00000100, B01111111, B00000010, B11111111, B00000001, B11111111, B00000001, B11111111, B00000001, B11111111, B00000001, B11111111, B00000001, B01111111, B00000010, B00111111, B00000100, B00011111, B00001000, B00001111, B00010000, B00000111, B11100000 }; //Waning Crescent const unsigned char PROGMEM moon7[] = { B00000111, B11100000, B00001110, B00010000, B00011100, B00001000, B00111000, B00000100, B01110000, B00000010, B11110000, B00000001, B11110000, B00000001, B11110000, B00000001, B11110000, B00000001, B11110000, B00000001, B01110000, B00000010, B00111000, B00000100, B00011100, B00001000, B00001110, B00010000, B00000111, B11100000 }; //===================================================================================== void drawMoon(int moon_x, int moon_y, int phase) { display.fillRect(moon_x, moon_y, 16, 15, WHITE); display.drawBitmap(moon_x, moon_y, moon4, 16, 15, WHITE); switch (phase) { case 0: display.drawBitmap(moon_x, moon_y, moon0, 16, 15, BLACK); break; case 1: display.drawBitmap(moon_x, moon_y, moon1, 16, 15, BLACK); break; case 2: display.drawBitmap(moon_x, moon_y, moon2, 16, 15, BLACK); break; case 3: display.drawBitmap(moon_x, moon_y, moon3, 16, 15, BLACK); break; case 4: display.drawBitmap(moon_x, moon_y, moon4, 16, 15, BLACK); break; case 5: display.drawBitmap(moon_x, moon_y, moon5, 16, 15, BLACK); break; case 6: display.drawBitmap(moon_x, moon_y, moon6, 16, 15, BLACK); break; case 7: display.drawBitmap(moon_x, moon_y, moon7, 16, 15, BLACK); break; default: display.drawBitmap(moon_x, moon_y, moon4, 16, 15, WHITE); } } //=========================================================================================== void drawMoonDate(int moon_x, int moon_y, uint8_t * datetoday) { float phase; phase = tardis.MoonPhase(datetoday); if (phase >= 0.0 && phase <= 0.0625) { drawMoon(moon_x, moon_y, 0); }; //0.000 New moon if (phase > 0.0625 && phase <= 0.1875) { drawMoon(moon_x, moon_y, 1); }; //0,125 if (phase > 0.1875 && phase <= 0.3125 ) { drawMoon(moon_x, moon_y, 2); }; //0.250 First Quarter if (phase > 0.3125 && phase <= 0.4375) { drawMoon(moon_x, moon_y, 3); }; //0,375 if (phase > 0.4375 && phase <= 0.5625) { drawMoon(moon_x, moon_y, 4); }; //0.500 Full if (phase > 0.5625 && phase <= 0.6875) { drawMoon(moon_x, moon_y, 5); }; //0,625 if (phase > 0.6875 && phase <= 0.8125) { drawMoon(moon_x, moon_y, 6); }; //0.750 Last Quarter if (phase > 0.8125 && phase <= 0.9375) { drawMoon(moon_x, moon_y, 7); }; //0.875 if (phase > 0.9375 && phase <= 1) { drawMoon(moon_x, moon_y, 0); }; //0.990 Almost new } //===================================================================================== void drawSignal(float streng) { display.fillRect(0, 0, 12, 6, WHITE); display.drawTriangle(0, 0, 8, 0, 4, 4, BLACK); display.drawLine(4, 0, 4, 6, BLACK); display.drawLine(6, 5, 6, 6, BLACK); display.drawLine(8, 4, 8, 6, BLACK); display.drawLine(10, 2, 10, 6, BLACK); display.drawLine(12, 0, 12, 6, BLACK); } //===================================================================================== void drawBatteryState(float v_bat) { display.fillRect(68, 0, 16, 7, WHITE); display.drawRect(83, 2, 1, 3, BLACK); display.drawRoundRect(68, 0, 15, 7, 2, BLACK); // 3, 44 4, 2 0, 76 0, 152 //4,200 full 4 //4,048 3 //3,896 2 //3,744 1 //3,592 0 //3,440 zero - if (v_bat > 4500) { display.fillRect(70, 2, 10, 3, BLACK); } if (v_bat > 4048) { display.drawRect(79, 2, 2, 3, BLACK); } if (v_bat > 3896) { display.drawRect(76, 2, 2, 3, BLACK); } if (v_bat > 3744) { display.drawRect(73, 2, 2, 3, BLACK); } if (v_bat > 3592) { display.drawRect(70, 2, 2, 3, BLACK); } } //===================================================================================== void drawTime(byte x, byte y) { display.fillRect(0 + x, 0 + y, 48, 7, WHITE); //display.fillRect(0+x, 0+y, 30, 7, WHITE); Time t = rtc.time(); display.setTextColor(BLACK); display.setTextSize(1); display.setCursor(x, y); display.print(t.hr); display.print(":"); display.print(t.min); display.print(":"); display.print(t.sec); } //=========================================================================================== void updateMoonSunDate() { Time t = rtc.time(); today[0] = 0; today[1] = 0; today[2] = 12; today[3] = t.date; today[4] = t.mon; today[5] = t.yr - 2000; } //===================================================================================== void drawSunRiseSet(byte x, byte y) { updateMoonSunDate(); display.setTextSize(1); display.setTextColor(BLACK); display.fillRect(x, y, 33, y + 8, WHITE); if (tardis.SunRise(today)) // if the sun will rise today (it might not, in the [ant]arctic) { display.setCursor(x, y); display.print((int) today[tl_hour]); display.print(":"); display.println((int) today[tl_minute]); } if (tardis.SunSet(today)) // if the sun will set today (it might not, in the [ant]arctic) { display.setCursor(x, y + 8); display.print((int) today[tl_hour]); display.print(":"); display.println((int) today[tl_minute]); } } //===================================================================================== void drawPressure(byte x, byte y) { display.setTextSize(1); display.setTextColor(BLACK); display.fillRect(x, y, 33, y + 8, WHITE); display.setCursor(x, y); t_f = Temperature; display.println( t_f / 10, 1); display.setCursor(x, y + 8); //display.println(ceil(Pressure / 133.3), 0); display.println(Pressure / 133.3, 1); } //===================================================================================== long readVcc() { // Read 1.1V reference against AVcc // set the reference to Vcc and the measurement to the internal 1.1V reference #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) ADMUX = _BV(MUX5) | _BV(MUX0); #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) ADMUX = _BV(MUX3) | _BV(MUX2); #else ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); #endif delay(75); // Wait for Vref to settle ADCSRA |= _BV(ADSC); // Start conversion while (bit_is_set(ADCSRA, ADSC)); // measuring uint8_t low = ADCL; // must read ADCL first - it then locks ADCH uint8_t high = ADCH; // unlocks both long result = (high << 8) | low; //scale_constant = internal1.1Ref * 1023 * 1000 // //internal1.1Ref = 1.1 * Vcc1 (_) / Vcc2 (__readVcc()) //4.967/4600-------1215079.369565217 // result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*100000 result = 1132060 / result; return result; // Vcc in millivolts //http://blog.unlimite.net/?p=25 } //=========================================================================================== void drawVcc(byte x, byte y, word vcc) { display.setTextSize(1); display.setTextColor(BLACK); display.fillRect(x, y, 33, y + 8, WHITE); display.setCursor(x, y); display.println(vcc); } //===================================================================================== void pressure_drawLine(byte x, byte h) { display.drawLine(x, 47 - h, x, 47, BLACK); } void pressure_drawGraph() { display.fillRect(0, 25, 83, 47, WHITE); for (int i = 0; i <= 83; i++) { pressure_drawLine(i, EEPROM.read(i)); } } //=========================================================================================== void setup() { Serial.begin(9600); pinMode(8, INPUT_PULLUP); pinMode(9, INPUT_PULLUP); pinMode(2, OUTPUT); //----------------------------------------------------------------------------- //rtc.writeProtect(false); //rtc.halt(false); String day = dayAsString(t.day); //----------------------------------------------------------------------------- tardis.TimeZone(3 * 55); tardis.Position(LATITUDE, LONGITUDE); //----------------------------------------------------------------------------- Wire.begin(); display.begin(); display.setContrast(55); display.clearDisplay(); display.drawLine(0, display.height() / 2, display.width(), display.height() / 2, BLACK); dps.init(); updateMoonSunDate(); drawMoonDate(34, 8, today); pressure_drawGraph(); display.display(); prevHour = rtc.time().hr; //EEPROM.write(0, 9); // for (int i=0; i <= 83; i++){ // EEPROM.write(i, random(1, 23)); // pressure_drawLine(i,EEPROM.read(i)); // Serial.println(EEPROM.read(i)); // } } //===================================================================================== void loop() { unsigned long currentMillis = millis(); unsigned long currentMillis2 = millis(); byte temp; //timer---------------------- 1 hour // if (currentMillis - previousMillis > interval) { // previousMillis = currentMillis; if (rtc.time().hr != prevHour) { prevHour = rtc.time().hr; dps.getPressure(&Pressure); dps.getTemperature(&Temperature); for (int i = 0; i <= 82; i++) { temp = EEPROM.read(i + 1); EEPROM.write(i, temp); } EEPROM.write(83, ceil(Pressure / 133.3) - 740); pressure_drawGraph(); display.display(); } //timer---------------------- 1 sec // if (currentMillis2 - previousMillis2 > interval2) { // previousMillis2 = currentMillis2; if (rtc.time().sec != prevSecond) { prevSecond = rtc.time().sec; dps.getPressure(&Pressure); dps.getTemperature(&Temperature); updateMoonSunDate(); drawPressure(0, 8); drawTime(17, 0); drawSunRiseSet(53, 8); drawMoonDate(34, 8, today); drawBatteryState(readVcc()); drawSignal(5); // drawVcc(0, 16, readVcc()); display.display(); } //timer---------------------- buttonState = digitalRead(8); // Serial.println(buttonState); if (buttonState != lastButtonState) { if (buttonState == HIGH) { buttonPushCounter++; } } lastButtonState = buttonState; if (buttonPushCounter % 2 == 0) { digitalWrite(2, HIGH); } else { digitalWrite(2, LOW); } } //===================================================================================== 

Source: https://habr.com/ru/post/392831/


All Articles