Нет, пока есть пара проблем в железе и огромная проблема со временем - внук у меня родился. Много времени уходит на помощь дочери (в поликлиннику свозить, документы оформить, прописать в квартире и т.д.) А с железом вот какая проблема. Было все собрано на DIP ATMega 328, на макетке. В нее сразу залил загрузчик с Ардуины 3-х вольтовой и потом скетч. Сначала все работало нормально, потом изображение на индикаторе пропало. Ресет не помог. Выключил - оставил так. Через пару часов включил, все работает. Потом снова все отключается. Закономерности по времени никакой нет, может и трое суток проработать, может через час выключиться. И на включение похожая ситуация, может сразу включиться, а может только через сутки. Не пойму. Хотя есть догадка - кварц на меге поставил тот который был - на 12 МГц, а нужен на 8. Может по этому через время срывается генерация...?
Я для narodmon.ru буду делать на Wemos D1, жду датчики, едут два BMP-280, DS18B20 у меня россыпью штук 50 есть, еще едут DS3231 и еще какие-то, на HMC5883L хотел флюгер сделать, но думаю проще будет на энкодере 360 градусов, но он по цене кусается 1500= )))
Я поколдую с твоим скетчем, запущу под I2C, скину здесь
Вот болванка под I2C, датчики не ставил, дисплей работает )))
Компилировал под 1.6.12 но некоторые библиотеки из под старых версий ставят систему в позу, подправил пути для файлов библиотек
/* Метео станция от Евгения, RA6FNQ, г.Ставрополь в модификации
* UA6EM под различные конфигурации
* 1. 08.12.2016 Прикрутил дисплей LCD-1602 по I2C
* 2. Создал раздел выбора конфигурации
* 3. кое-какие заготовки под другие дисплеи
*/
// *** Раздел выбора конфигурации *** //
/* */
//#define HARDWARE_LCD1602 // обычный дисплей
#define HARDWARE_LCD1602_I2C // дисплей подключенный по I2C
#define HARDWARE_DHT22 // датчик 1
#define HARDWARE_BMP280
#define interval 330 // обновление дисплея мс
#ifdef HARDWARE_LCD1602_I2C
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
#endif
#ifdef HARDWARE_LCD1602
#include <LiquidCrystal.h>
LiquidCrystal lcd(7, 6, 5, 4, 3, 2); // подправьте под свою схему
#endif
long previousMillis = 0;
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP280.h>
#ifdef HARDWARE_DHT22
#include "DHT.h"
#define DHTPIN 9 // 9 pin для датчика DHT22
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
#endif
#ifdef HARDWARE_BMP280
#define BMP_CS 10 // hardware SPI
#define SEALEVELPRESSURE_HPA (1013.25) //
Adafruit_BMP280 bme(BMP_CS); // работаем по шине hardware SPI
#endif
long temp3 = 0, Pressure = 0, Altitude = 0;
void setup() {
#ifdef HARDWARE_LCD1602
lcd.begin(16, 2);
#endif
#ifdef HARDWARE_LCD1602_I2C
lcd.begin(16,2);
#endif
lcd.print(" Meteo v01_1602H"); // приветствие
lcd.setCursor(0,1);
lcd.print(" RA6FNQ 2016 11"); // версия 0.3
delay(3000);
lcd.clear();
Wire.begin();
dht.begin();
bme.begin(); //запуск BME280
delay(2000);
}
void loop()
{
Pressure = bme.readPressure();
Altitude = bme.readAltitude(SEALEVELPRESSURE_HPA);
temp3 = bme.readTemperature();
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
float h = dht.readHumidity();
float t = dht.readTemperature(); // Read temperature as Celsius
delay(1000);
lcd.clear(); // очистим лсд дисплей
lcd.setCursor(0, 0);
lcd.print("T");//задаем температуру снаружи, DHT22
lcd.setCursor(2, 0);
lcd.print(t, 1);
lcd.setCursor(8, 0);
lcd.print("t");//задаем температуру
lcd.setCursor(10, 0);
lcd.print(bme.readTemperature(), 1); //Это температура с барометра);
lcd.setCursor(14, 0);
lcd.print("*C");
delay (1000); // Задержка 1 с
}
Ты BMP-280 к чему и как подключаешь?
У меня он не заработал, видимо брак, ни по I2C - ни по SPI-SOFT
- скетч получается аж 10 644 байт (34%) - есть мысли как запустить на библиотеке "Grove_BME280-master", мне кажется размер будет гораздо меньше.
- не удалось вычислить давление в мм ртутн. столба - перепробовал несколько вариантов - есть что подсказать?
- без строки "Serial.println(mySensor.begin(), HEX);" не выводится параметр "Pressure" - Давление, а с этой строкой также в начале выводится цифра 58 - ну и как это победить?
- не удалось вычислить давление в мм ртутн. столба - перепробовал несколько вариантов - есть что подсказать?
- без строки "Serial.println(mySensor.begin(), HEX);" не выводится параметр "Pressure" - Давление, а с этой строкой также в начале выводится цифра 58 - ну и как это победить?
1. умножить на коэффициент (ртуть в 13 с гаком раз тяжелее воды к примеру) или напрямую к примеру 1000 гектопаскалей это 750 мм ртутного столба
Привет всем. Когдо сам занимался этой темой перепробывал много библиотек. И с уверенностью могу отметить, что самая оптимальная, для меня, оказалась библиотека - "cactus_io_BME280_I2C.h"
Привет всем. Когдо сам занимался этой темой перепробывал много библиотек. И с уверенностью могу отметить, что самая оптимальная, для меня, оказалась библиотека - "cactus_io_BME280_I2C.h"
Получил китайский BMP-280, но настроить пока не получается.
Распиновка:
SCL - 13
SDA - 11
CSB - 10
SDO - 12
Запустил Adafruit'овский тестовый скетч. Библиотека естественно от Adafruit, но в архиве не было файла Adafruit_Sensor.h. Докачал откуда то, тоже вроде с github.
Температура в комнате где тестировался датчик примерно 25 градусов
Давление у нас по данным гидрометеостанций примерно 767 мм рт. ст.
А высота примерно 495 м над уровнем моря.
Сначала не стал паять ножки к плате датчика, а просто воткнул и соединил кабелями. Результаты были разные когда датчик просто лежал (результат №1) и когда прижимал кабели плотнее к датчику для лучшего соединения (результат №2):
Temp = 25.43 *C
Pressure = 562.72 mm.rt.st
~Height = 2465.58 m
Temp = 42.82 *C
Pressure = 728.79 mm.rt.st
~Height = 336.41 m
Из этого можно увидеть что на первом результате температура правильная, а вот давление и высота над уровнем моря вообще не то.
А на втором результате температура очень завышена, давление более менее нормальная, высота тоже не ахти но уже тоже более менее близка к правде.
Потом запаял ножки к датчику и тогда получаю только результаты ближе к №2.
Temp = 41.76 *C
Pressure = 723.45 mm.rt.st
~Height = 415.29 m
Temp = 41.73 *C
Pressure = 723.46 mm.rt.st
~Height = 415.07 m
Как получить правильные данные? А именно:
1. Температуру
2. Давление и высоту. Вроде надо поменять значение 1013.25 на другое. Так вот на какое? Из какой формулы рассчитать для моей местности эту значению? Или же надо копать в другую сторону?
это я подогнал показания bme280 под показания домашней метеостанции орегон. а вы можете в своей местности посмотреть на народмон и также подкорректировать показания
Всем привет, вчера закончил программу для своей погодной станции. Пока гуглил по датчику BMP280 натыкался на эту ветку форума.
У меня возникло одно замечание, для всех ваших скетчей, вы слишком часто опрашиваете датчики, у меня, когда я опрашиваю чаще чем 5-10 секунд, медленно но заметно начинает повышатся температура DHT3231 и DS18D20. За BMP280 такой беды не замеченно, но на всякий случай я опрашиваю датчики 1 раз в минуту.
Я собрал станцию (пока на макетке) на часах DHT3231, внешнем датчике температуры DS18D20, барометр BMP280, экран 20*4 I2C, гигрометр DHT-11 (знаю, гадость, но у нас из-за боевых действий другие купить проблематично) и 7 сегментный дисплей на TM1637 чтобы было издалека видно время.
Погодная станция прогнозирует изменение погоды по алгоритму Zambretti, основываясь на динамике изменения давления за последние 3 часа. Может строить график изменения давления, температуры внутри и снаружи за последние 20 часов. Запоминает время достижения минимального и максимального значения 2 температур, влажности и давления за эти сутки. Выводит основные показатели на COM порт. Возможность выставлять время, дату и день недели кнопками. На остальное не хватило памяти. Скорее всего, как разбогатею, куплю еще 1 микроконтроллер, на него повешу опрос всех датчиков и экраны и буду передавать через COM порт на 2-й МК, в котором будут обрабатываться данные, и прочие плюшки =)
Комменты на английском, мне так легче, ненавижу язык переключать =)
//lcd
#include <LiquidCrystal_PCF8574.h>
LiquidCrystal_PCF8574 lcd(0x27);
//Clock
#include <Wire.h>
#include "Sodaq_DS3231.h"
#include <DallasTemperature.h>
char weekDay[][4] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
//barometr
#include <BME280I2C.h>
BME280I2C bme;
float hPa = 0;
float Altitude = 0;
float MaxPressure = 0, MinPressure = 65000;
float MaxTempO = -200, MinTempO = 200, MaxTempIn = -200, MinTempIn = 200;
DateTime MaxPressureT, MinPressureT;
DateTime MaxTempOT, MinTempOT, MaxTempInT, MinTempInT, TempTime;
float Pres = 0;
float InT, OutT;
//LedDisplay
#include "TM1637.h" // Подключаем библиотеку
#define CLK 13 // К этому пину подключаем CLK
#define DIO 12 // К этому пину подключаем DIO
TM1637 tm1637(CLK, DIO);
//humidity
#include <SimpleDHT.h>
int pinDHT11 = 9;
SimpleDHT11 dht11;
byte Hum = 0;
byte DHT11temperature = 0;
byte MaxHum = 0, MinHum = 101;
DateTime MaxHumT, MinHumT;
//buttons
#define BTN 6
#define BTNUP 5
#define BTNDOWN 4
//int LCDled = 3; // the PWM pin the LED is attached to
//Main Display mode 1- show main screen,2 shov max and min time... etc..
int DisplayMode = 0;
int _m, _s, _mon, _day, _week;
int _h, _year;
//unsigned long RefreshLCD;
unsigned long TimeReturn;
DateTime now;
DateTime PowerOn;
byte LastRead, ResetVals;
unsigned long old_ts = 0;
float PressureHistory [20] = {
700, 700, 700, 700, 700,
700, 700, 700, 700, 700,
700, 700, 700, 700, 700,
700, 700, 700, 700, 700
};
float TempHistoryIn [20] = {
-127, -127, -127, -127, -127,
-127, -127, -127, -127, -127,
-127, -127, -127, -127, -127,
-127, -127, -127, -127, -127
};
float TempHistoryOut [20] = {
30, 40, 42, 39, 38,
10, 40, 42, 39, 38,
-1, 40, 42, 39, 38,
30, 40, 42, 39, 38
};
//OutTemp
#define ONE_WIRE_BUS 8
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
//Chars for graph
byte ArrCharIndex[9] = {
254, 2, 95, 3, 4, 176, 5, 6, 7
};
//Zambretty array
byte Zarr[32] =
{ 0,//a
0,//b
0,//d
1,//h
5,//o
5,//r
5,//u
5,//v
5,//x
0,//a
0,//b
1,//e
2,//k
4,//n
5,//p
5,//s
5,//w
5,//x
8,//z
0,//a
0,//b
0,//c
0,//f
1,//g
2,//i
3,//j
3,//l
3,//m
6,//q
6,//t
7,//y
8//z
};
String ForecastText[] =
{
"Will fine",//0
"Fine>shower",//1
"Shower>imp.",//2
"Changeable>imp.",//3
"Showery/bright",//4
"Rain",//5
"Unsettled",//6
"Storm",//7
"Storm>rain"//8
};
//hum icon
byte HumCHR[8] = {
B00100,
B00100,
B01010,
B01010,
B10001,
B10001,
B10001,
B01110
};
//temp icon
byte Temp[8] = {
B00100,
B01010,
B01010,
B01110,
B01110,
B11111,
B11111,
B01110
};
//graph char 1/8
byte ch1[8] = {
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B11111
};
//graph char 2/8 is _ char
//graph char 3/8
byte ch3[8] = {
B00000,
B00000,
B00000,
B00000,
B00000,
B11111,
B00000,
B00000
};
//graph chars 4/8
byte ch4[8] = {
B00000,
B00000,
B00000,
B00000,
B11111,
B00000,
B00000,
B00000
};
//graph char 5/8 is - char
//graph chars 6/8
byte ch6[8] = {
B00000,
B00000,
B11111,
B00000,
B00000,
B00000,
B00000,
B00000
};
//graph char 7/8
byte ch7[8] = {
B00000,
B11111,
B00000,
B00000,
B00000,
B00000,
B00000
};
//graph char 8/8
byte ch8[8] = {
B11111,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000
};
void setup ()
{
pinMode(BTN, INPUT_PULLUP);
pinMode(BTNUP, INPUT_PULLUP);
pinMode(BTNDOWN, INPUT_PULLUP);
Wire.begin();
Wire.beginTransmission(0x27);
lcd.begin(20, 4); // initialize the lcd
//load custom chars
lcd.createChar (0, Temp);
lcd.createChar (1, HumCHR);
lcd.createChar (2, ch1);
lcd.createChar (3, ch3);
lcd.createChar (4, ch4);
lcd.createChar (5, ch6);
lcd.createChar (6, ch7);
lcd.createChar (7, ch8);
//must be called after loading chars
lcd.home();
lcd.clear();
lcd.print("Wait");
while (!bme.begin()) {
lcd.clear();
lcd.print("PrSensorError");
}
while (!rtc.begin()) {
lcd.clear();
lcd.print("ClockError");
}
lcd.setBacklight(255);
// SetBrightness(brightness);
tm1637.init();
tm1637.set(7);
//just read data from sensors ds18d20 sometimes in first read return 85.0C
readSensors(rtc.now(), true, false);
PowerOn = rtc.now();
LastRead = rtc.now().hour();
ResetVals = rtc.now().date();
//store first values from sensors to limit values
readSensors(rtc.now(), true, true);
//save current values from the sensors to history
//for normal graph view in first 20 hours of work
for (int tt = 0; tt < 20; tt++)
{
PressureHistory[tt] = Pres;
TempHistoryIn[tt] = InT;
TempHistoryOut[tt] = OutT;
}
//show main screen by default
DisplayMode = 1;
//try to forecast =)
Forecast(now.month());
Serial.begin(9600);
}
void loop ()
{
//return to main screen from any other mode in 10 sec inactivity
if ( millis() - TimeReturn > 10000) {
if (DisplayMode != 1) {
lcd.clear();
lcd.home();
DisplayMode = 1;
}
TimeReturn = millis();
}
//main screen
if (DisplayMode == 1 ) {
now = rtc.now(); //get the current date-time
uint32_t ts = now.getEpoch();
//check second changed or not
if (old_ts != ts) {
old_ts = ts;
//Write time on tm1367
tm1637.display(0, now.hour() / 10);
tm1637.display(1, now.hour() % 10);
tm1637.display(2, now.minute() / 10);
tm1637.display(3, now.minute() % 10);
//blink dot
tm1637.point(ts % 2 == 0 ? POINT_OFF : POINT_ON);
//write current time and date on 20*4
WriteTimeDT(now, 0, 0);
WriteDateDT(now, 6, 0);
//if hour changes store current sensor values to history
if (LastRead != now.hour())
{
LastRead = now.hour();
readSensors(rtc.now(), true, true);
for (byte i = 0; i < 19; i++) {
PressureHistory[i] = PressureHistory[i + 1];
TempHistoryIn[i] = TempHistoryIn[i + 1];
TempHistoryOut[i] = TempHistoryOut[i + 1];
}
TempHistoryIn[19] = InT;
TempHistoryOut[19] = OutT;
PressureHistory[19] = Pres;
//if date changes reset limit values
if ( ResetVals != now.date()) {
ResetVals = now.date();
MaxTempO = -200;
MinTempO = 200;
MaxTempIn = -200;
MinTempIn = 200;
MaxPressure = 0;
MinPressure = 65000;
MaxHum = 0;
MinHum = 101;
readSensors(rtc.now(), true, true);
}
}
//read sensors values
//each sensor interrogated 1 time per 60 seconds
//and 20 seconds delay between different sensors
if (now.second() % 10 == 0 && now.second() > 0)
{
readSensors(now, false, true);
lcd.setCursor(0, 3);
lcd.print(" ");
lcd.setCursor(0, 3);
//try to forecast
//this function wrute on 4 line forecast
lcd.print(Forecast(now.month()));
//serial write some data
Serial.print("<h");
Serial.print(now.hour());
Serial.print("m");
Serial.print(now.minute());
Serial.print("s");
Serial.print(now.second());
Serial.print("D");
Serial.print(now.date());
Serial.print("M");
Serial.print(now.month());
Serial.print("Y");
Serial.print(now.year());
Serial.print("d");
Serial.print(weekDay[now.dayOfWeek() - 1]);
Serial.print("InT");
Serial.print(InT);
Serial.print("Out");
Serial.print(OutT);
Serial.print("Hum");
Serial.print(Hum);
Serial.print("Pres");
Serial.print(Pres);
Serial.print("F-t");
Serial.print(Forecast(now.month()));
Serial.println(">");
}
}
//2 line
lcd.setCursor(0, 1);
//write in temp
lcd.print("In");
//write custom temp char
lcd.print(char(0));
lcd.print(InT);
//write out temp
lcd.print(" Out");
//write custom temp char
lcd.print(char(0));
lcd.print(OutT);
//3 line
lcd.setCursor(0, 2);
//write custom humidity char
lcd.print(char(1));
//write humidity
lcd.print(Hum);
lcd.print("% ");
lcd.print(Pres);
lcd.print("mmHg ");
}
//show limit waluea for out temp
if (DisplayMode == 2)
{
lcd.setCursor(0, 0);
lcd.print("Max out t");
WriteTimeDT(MaxTempOT, 0, 13);
lcd.setCursor(0, 1);
lcd.print(MaxTempO);
lcd.setCursor(0, 2);
lcd.print("Min out t");
WriteTimeDT(MinTempOT, 2, 13);
lcd.setCursor(0, 3);
lcd.print(MinTempO);
}
//draw graph for out temp
if (DisplayMode == 3)
{
lcd.setCursor(0, 0);
lcd.print("Out t hist");
drawGraphFullScreen(TempHistoryOut);
}
//show limit walues for in temp
if (DisplayMode == 4)
{
lcd.setCursor(0, 0);
lcd.print("Max in t");
WriteTimeDT(MaxTempInT, 0, 13);
lcd.setCursor(0, 1);
lcd.print(MaxTempIn);
lcd.setCursor(0, 2);
lcd.print("Min in t");
WriteTimeDT(MinTempInT, 2, 13);
lcd.setCursor(0, 3);
lcd.print(MinTempIn);
}
//draw graph for in temp
if (DisplayMode == 5)
{
lcd.setCursor(0, 0);
lcd.print("In t hist");
drawGraphFullScreen(TempHistoryIn);
}
//show limit walues for pressure
if (DisplayMode == 6)
{
lcd.setCursor(0, 0);
lcd.print("Max pressure");
WriteTimeDT(MaxPressureT, 0, 13);
lcd.setCursor(0, 1);
lcd.print(MaxPressure);
lcd.setCursor(0, 2);
lcd.print("Min pressure");
WriteTimeDT(MinPressureT, 2, 13);
lcd.setCursor(0, 3);
lcd.print(MinPressure);
}
//draw graph for pressure
if (DisplayMode == 7)
{
lcd.setCursor(0, 0);
lcd.print("Pressure hist");
drawGraphFullScreen(PressureHistory);
}
//show limit walues for humidity
if (DisplayMode == 8)
{
lcd.setCursor(0, 0);
lcd.print("Max humidity");
WriteTimeDT(MaxHumT, 0, 13);
lcd.setCursor(0, 1);
lcd.print(MaxHum);
lcd.setCursor(0, 2);
lcd.print("Min humidity");
WriteTimeDT(MinHumT, 2, 13);
lcd.setCursor(0, 3);
lcd.print(MinHum);
}
//show Altitude, uptime and (c)
if (DisplayMode == 9)
{
lcd.setCursor(0, 0);
lcd.print("Altitude ");
lcd.print(Altitude);
lcd.print("m ");
lcd.setCursor(0, 1);
lcd.print("PowerOn");
WriteTimeDT(PowerOn, 2, 0);
WriteDateDT(PowerOn, 6, 2);
lcd.setCursor(0, 3);
lcd.print("(c)IvanchenkoAV 2017");
}
//if button up pressed
if (!digitalRead(BTNUP) && DisplayMode < 100)
{
DisplayMode++;
lcd.clear();
}
//if button down pressed
if (!digitalRead(BTNDOWN) && DisplayMode < 100)
{
DisplayMode--;
lcd.clear();
}
//display menu limits
if (DisplayMode == 10)
{
DisplayMode = 1;
}
//display menu limits
if (DisplayMode == 0)
{
DisplayMode = 9;
}
//set button pressed
if (!digitalRead(BTN)) {
TimeReturn = millis();
//if set button pressed in main screen mode
if (DisplayMode < 100)
{
DisplayMode = 100;
//save current time to temp values
TempTime = rtc.now();
_h = TempTime.hour();
_m = TempTime.minute();
_day = TempTime.date();
_mon = TempTime.month();
_year = TempTime.year();
_week = TempTime.dayOfWeek();
}
else
//if button pressed in set mode
DisplayMode++;
//menu limit
if (DisplayMode == 107) {
lcd.setCursor(0, 1);
lcd.print("Cancel");
delay(3000);
DisplayMode = 1;
lcd.clear();
}
//delay(300);
}
delay(200);
//disp.set(brightness / 64 + 1);
//reset time return if any buton pressed
if (!digitalRead(BTNUP) || !digitalRead(BTNDOWN)) {
TimeReturn = millis();
}
//temp hour set
if (DisplayMode == 100)
{
if (!digitalRead(BTNUP))
_h++;
if (!digitalRead(BTNDOWN))
_h--;
if (_h > 23)
_h = 0;
if (_h < 0)
_h = 23;
lcd.clear();
lcd.home();
lcd.print("Hour ");
lcd.print(_h);
}
//temp minute set
if (DisplayMode == 101)
{
if (!digitalRead(BTNUP))
_m++;
if (!digitalRead(BTNDOWN))
_m--;
if (_m >= 60)
_m = 0;
if (_m < 0)
_m = 59;
lcd.clear();
lcd.home();
lcd.print("Minute ");
lcd.print(_m);
}
//temp date set
if (DisplayMode == 102)
{
if (!digitalRead(BTNUP))
_day++;
if (!digitalRead(BTNDOWN))
_day--;
if (_day > 31)
_day = 1;
if (_day < 1)
_day = 31;
lcd.clear();
lcd.home();
lcd.print("Day ");
lcd.print(_day);
}
//temp month set
if (DisplayMode == 103)
{
if (!digitalRead(BTNUP))
_mon++;
if (!digitalRead(BTNDOWN))
_mon--;
if (_mon > 12)
_mon = 1;
if (_mon < 1)
_mon = 12;
lcd.clear();
lcd.home();
lcd.print("Month ");
lcd.print(_mon);
}
//temp year set
if (DisplayMode == 104)
{
if (!digitalRead(BTNUP))
_year++;
if (!digitalRead(BTNDOWN))
_year--;
if (_year > 3000)
_year = 1;
if (_year < 1)
_year = 3000;
lcd.clear();
lcd.home();
lcd.print("Year ");
lcd.print(_year);
}
//temp weekday set
if (DisplayMode == 105)
{
if (!digitalRead(BTNUP))
_week++;
if (!digitalRead(BTNDOWN))
_week--;
if (_week > 7)
_week = 1;
if (_week < 1)
_week = 7;
lcd.clear();
lcd.home();
lcd.print("WeekDay ");
lcd.print(weekDay[_week - 1]);
}
// set new time?
if (DisplayMode == 106)
{
lcd.clear();
lcd.home();
lcd.print("Save Y/N?");
//if button up pressed save new time
if (!digitalRead(BTNUP))
{
DateTime dt(_year, _mon, _day, _h, _m, 0, _week);
rtc.setDateTime(dt);
lcd.setCursor(0, 1);
lcd.print("Ok");
delay(3000);
DisplayMode = 1;
lcd.clear();
}
//if button down pressed - exit to main screen
if (!digitalRead(BTNDOWN)) {
lcd.setCursor(0, 1);
lcd.print("Cancel");
delay(3000);
DisplayMode = 1;
lcd.clear();
}
}
}
//write time in x,y of lcd
void WriteTimeDT(DateTime Time, byte y, byte x) {
lcd.setCursor(x, y);
if (Time.hour() < 10)
lcd.print('0');
lcd.print(Time.hour());
lcd.print(Time.second() % 2 == 0 ? ':' : ' ');
if (Time.minute() < 10)
lcd.print('0');
lcd.print(Time.minute());
}
//write date in x,y of lcd
void WriteDateDT(DateTime Time, int x, int y) {
lcd.setCursor(x, y);
if (Time.date() < 10)
lcd.print('0');
lcd.print(Time.date());
lcd.print('/');
if (Time.month() < 10)
lcd.print('0');
lcd.print(Time.month());
lcd.print('/');
lcd.print(Time.year());
lcd.print(' ');
lcd.print(weekDay[Time.dayOfWeek() - 1]);
}
//draw graph
void drawGraphFullScreen(float x[20]) {
//
float maxp = -30000, minp = 30000;
float divider;
byte curVal;
//saerch max and min values in history
for (byte i = 0; i < 20; i++)
{
if ( x[i] > maxp)
maxp = x[i];
if ( x[i] < minp)
minp = x[i];
}
//graph draw in 3 lines, so we have 24 pixels height graph
//Do not deny yourself anything =)
// divider - value of division of 1 pixel +0.01 to prevert division by 0
divider = (maxp - minp) / 24 + 0.01;
//write value of division
lcd.setCursor(14, 0);
lcd.print(divider);
for (byte i = 0; i < 20; i++)
{
//draw 4 line, bottom of graph
curVal = byte((x[i] - minp) / divider);
lcd.setCursor(i, 3);
//if current value of graph catch in value 0 to 8*divider
//we draw chart
if (curVal <= 8)
{
//seach appropriate char in array of custom chars
if (curVal > 0)
lcd.print(char(ArrCharIndex[curVal]));
else
//if current val = min
lcd.print(char(2));
}
else
//if chart line upper than current line print blank char
lcd.print(char(ArrCharIndex[0]));
//draw 3 line - middle of graph
lcd.setCursor(i, 2);
if (curVal <= 16 && curVal > 8)
//if current value of graph catch in value 8*divider to 16*divider
//we draw chart
//seach appropriate char in array of custom chars
lcd.print(char(ArrCharIndex[curVal - 8]));
else
//if chart line upper or lover than current line print blank char
lcd.print(char(ArrCharIndex[0]));
lcd.setCursor(i, 1);
//draw 4 line, bottom of graph
if (curVal <= 24 && curVal > 16)
//if current value of graph catch in value 16*divider to 24*divider
lcd.print(char(ArrCharIndex[curVal - 16]));
else
//if chart line lover than current line print blank char
lcd.print(char(ArrCharIndex[0]));
}
}
//read data from sensors depending on currend second
//bool Now means read all data immideatly
//bool store mean save limiting values data or not
void readSensors (DateTime Time, boolean Now, boolean store)
{
if (!Now) {
switch ( Time.second()) {
case 20:
//out temp dht18d20
sensors.requestTemperatures();
OutT = sensors.getTempCByIndex(0);
//store limiting values and time when they arrived
if (store) {
if (OutT > MaxTempO) {
MaxTempO = OutT;
MaxTempOT = Time;
}
if (OutT < MinTempO) {
MinTempO = OutT;
MinTempOT = Time;
}
}
break;
case 30:
dht11.read(pinDHT11, &DHT11temperature, &Hum, NULL);
//store limiting values and time when they arrived
if (store) {
if (Hum > MaxHum) {
MaxHum = Hum;
MaxHumT = Time;
}
if (Hum < MinHum) {
MinHum = Hum;
MinHumT = Time;
}
}
break;
case 40:
float hum(NAN);
uint8_t pressureUnit(0); // unit: B000 = Pa, B001 = hPa, B010 = Hg, B011 = atm, B100 = bar, B101 = torr, B110 = N/m^2, B111 = psi
bme.read(Pres, InT, hum, true, pressureUnit);
hPa = Pres / 100 + Altitude / 9.4;
Pres = Pres * 0.00750063755419211;
Altitude = bme.alt(true);
//store limiting values and time when they arrived
if (store) {
if (Pres > MaxPressure) {
MaxPressure = Pres;
MaxPressureT = Time;
}
if (Pres < MinPressure) {
MinPressure = Pres;
MinPressureT = Time;
}
if (InT > MaxTempIn) {
MaxTempIn = InT;
MaxTempInT = Time;
}
if (InT < MinTempIn) {
MinTempIn = InT;
MinTempInT = Time;
}
}
break;
}
}
else {
if (store) {
}
//out temp dht18d20
sensors.requestTemperatures();
OutT = sensors.getTempCByIndex(0);
//read humidity
dht11.read(pinDHT11, &DHT11temperature, &Hum, NULL);
//reap pressure and temp
float hum(NAN);
uint8_t pressureUnit(0); // unit: B000 = Pa, B001 = hPa, B010 = Hg, B011 = atm, B100 = bar, B101 = torr, B110 = N/m^2, B111 = psi
bme.read(Pres, InT, hum, true, pressureUnit);
hPa = Pres / 100 + Altitude / 9.4;
//convert hPa to mmHh
Pres = Pres * 0.00750063755419211;
Altitude = bme.alt(true);
//store limiting values and time when they arrived
if (store) {
if (Pres > MaxPressure) {
MaxPressure = Pres;
MaxPressureT = Time;
}
if (Pres < MinPressure) {
MinPressure = Pres;
MinPressureT = Time;
}
if (InT > MaxTempIn) {
MaxTempIn = InT;
MaxTempInT = Time;
}
if (InT < MinTempIn) {
MinTempIn = InT;
MinTempInT = Time;
}
if (Hum > MaxHum) {
MaxHum = Hum;
MaxHumT = Time;
}
if (Hum < MinHum) {
MinHum = Hum;
MinHumT = Time;
}
if (OutT > MaxTempO) {
MaxTempO = OutT;
MaxTempOT = Time;
}
if (OutT < MinTempO) {
MinTempO = OutT;
MinTempOT = Time;
}
}
}
}
// Select weather index Zambretti
String Forecast(byte Mon)
{
float z = 0;
char a;
//Pressure is up
if (PressureHistory[19] - PressureHistory[18] > 0.8 && PressureHistory[18] - PressureHistory[17] > 0.8)
{
z = 179 - 2 * hPa / 12.9;
if (Mon >= 5 && Mon <= 9)
z -= 2;
if (Mon < 5 || Mon > 9)
z -= 1;
return "_-" + ForecastText[Zarr[int(z)]];
}
else
// Pressure is down
if (PressureHistory[19] - PressureHistory[18] < -0.8 && PressureHistory[18] - PressureHistory[17] < -0.8) {
z = 130 - hPa / 8.1;
return "-_" + ForecastText[Zarr[int(z)]];
if (Mon >= 5 && Mon <= 9)
z += 2;
if (Mon < 5 || Mon > 9)
z += 1;
} else {
//stable pressure
z = 147 - 5 * hPa / 37.6;
return "--" + ForecastText[Zarr[int(z)]];
}
//return forecast string
}
Что красивового то? Красиво - это когда черным по белому и понятным родным языком написано! :-)
Как война закончится (надеюсь когда-нибудь это случится), куплю нормальный экран с поддержкой кирилицы, а не выдранный из неведомой хрени на барахолке и корейским шрифтом.
И как уже говорилось выше, если у вас экран это поддерживает, замените в исходнике текст, дело 5 минут. А тратить драгоценную память переменных под русские буквы, для меня непозволительно. И так думаю уже о объединении 2 МК в одном устройстве, для освобождения ресурсов. Один чисто как хранилище данных использовать. Кстати, в данном виде, если вы проведете русификацию, у вас не загрузится прошивка, не хватит бамяти. В этом коде если использовать еще 42 байта памяти переменных программа начинает работать нестабильно, из-за нехватки памяти. Тут каждая команда выверена и 3 раза оценена именно с точки зрения уменьшения объема кода. Я пробовал разные варианты одного и того же, и выбирал самый легковесный. В планах еще поковырять библиотеки, возможно там есть за счет чего освободить память.
Лично для меня основная фишка прибора - именно прогноз. Я на непосредственно программу потратил от силы 5-6 часов. С подключением устройств и долбежкой с библиотеками. И примерно 20 часов искал в интернете что то вменяемое, что можно запрограммировать.
И второй фишкой является то, что на приборе можно выставлять время без сторонних примочек.
Сейчас буду пытаться подключить к программатору эту плату, надеюсь мне очень очень повезет и эта штука окажется рабочей, несмотря на то, что в плату явно попало 220.
Нашел на барахолке, не знаю что это, но явно втыкалось в комп.
Если заработает, я спасен и я смогу сделать еще кучу хотелок.
В планах, если заработает:
*Внести все варианты ветвления прогноза калькулятора Zambretti без обобщений и сокращений, с плавной прокруткой длинных строк, что то типа бегущей строки но 1-й;
*График изменения влажности (не хватило памяти);
*Графики с заполнением, а не черточки как сейчас. И шаг графиков 6 минут, вместо 1 часа, получается очень красиво красиво, но сейчас не хватает памяти даже для 1 параметра;
*Автоматическая плавная яркость 2 экранов;
*Будильник;
*RGB Подсветка с плавным переходом оттенков в зависимости от внешней t. (холодно - синий, по мере потепления - желтый, зона комфорта - зеленый, жарко - красный;
*Внешние радио датчики температуры, влажности, освещенности и т.п. связуемые через 433мГц передатчик;
*Датчик солнечной радиации;
*Счетчик Гейгера (уже готов, собран на другом МК, но на погодной станции не хватает памяти, чтобы получать данные с него). Планировал подключение через 433мГц пердатчик, чтобы счетчик Гейгера был автономным самсодостаточным устройством, но если окажется включенным в зоне погодной станции, чтобы она автоматом тянула с него показания.
Все это можно сделать за пару часов, но... Где бы мне купить Мегу 256 по цене как на Али, а не за 4700 рублей как у нас. =)
ЗЫ мне отчасти английский даже понятнее, жене - всеравно, мелкому пока вообще всеравно какая погода, время суток и температура)
ЗЫЫ а кто сказал, что для меня русский - родной ;)
>>Genri5 Да какие обиды. Просто у каждого свои вкусы и фломастеры на вкус и цвет разные )
>>ua6em Меня на плате интересует Мега 128, там есть где разгуляться в плане ресурсов. Кстати, сейчас гуглил по вопросу нехватки памяти, возможно я нашел выход. Нашел код, который позволяет хранить строковые данные в области памяти программы. А у меня там около 8 кб свободно еще, такчто возможно живем еще.
Алгоритм брал отсюда. Лучше алгоритм можете не искать, т.к. похоже инфа по прогнозированию погоды является чуть ли не достоянием нации и не подлежит широкой огласке. Сведения о прогнозировании очень туманны и слабо поддаются систематизации.
На данный момент окончательный код, до сборки в железе больше изменений не планирую.
По сравнению с предыдущим вариантом добавлено:
* Автояркость на основании аналогового фоторезистора
* Меню для пользовательского выставления высоты, вызывается одновременным нажатием кнопок + и -, изменение ими же, сохранение - кнопка Set.
* Реализованны все ветвления калькулятора Zambretti в оригинальном виде без изменений.
* Уменьшенны пороги определения динамики изменения погоды. Теперь считается, что давление падает или растет если изменилось на 0.2 мм за 3 часа или 0.3 мм за 4 часа.
* Исправленна ошибка размерности, при приведении давления к уровню моря в прогнозе прибавлял mmHg к hPa.
* Все массивы использующиеся в прогнозировании объявленны константами и закинуты в память программы. Таким образом, несмотря на значительное добавление записей в эти массивы освободил около 180 байт памяти переменных.
* Косметические изменения функции вывода времени (на основном экране точки мигают, на остальных экранах всегда отображаются статично)
* Автопрокрутка длинных строк для прогноза.
* Приделан костыль для датчика 18d20, который 50/50 при первых 1-2 замерах показывает температуру 85.0, после работает стабильно неделями. Уже не первый раз сталкиваюсь.
* Почасовой график влажности.
#include <EEPROM.h>
//lcd
#include <LiquidCrystal_PCF8574.h>
LiquidCrystal_PCF8574 lcd(0x27);
//Clock
#include <Wire.h>
#include "Sodaq_DS3231.h"
char weekDay[][4] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
//barometr
#include <BME280I2C.h>
BME280I2C bme;
float hPa = 0;
float Altitude = 0;
float MaxPressure = 0, MinPressure = 65000;
float MaxTempO = -200, MinTempO = 200, MaxTempIn = -200, MinTempIn = 200;
DateTime MaxPressureT, MinPressureT;
DateTime MaxTempOT, MinTempOT, MaxTempInT, MinTempInT, TempTime;
float Pres = 0;
float InT, OutT;
//LedDisplay
#include "TM1637.h" // Подключаем библиотеку
#define CLK 13 // К этому пину подключаем CLK
#define DIO 12 // К этому пину подключаем DIO
TM1637 tm1637(CLK, DIO);
//humidity
#include <SimpleDHT.h>
int pinDHT11 = 9;
SimpleDHT11 dht11;
byte Hum = 0;
byte DHT11temperature = 0;
byte MaxHum = 0, MinHum = 101;
DateTime MaxHumT, MinHumT;
//buttons
//set button
#define BTN 6
//+ button
#define BTNUP 5
//- button
#define BTNDOWN 4
//press + and - to set user altitude
//int LCDled = 3; // the PWM pin the LED is attached to
//Main Display mode 1- show main screen,2 shov max and min time... etc..
int DisplayMode = 0;
int _m, _s, _mon, _day, _week;
int _h, _year;
//unsigned long RefreshLCD;
unsigned long TimeReturn;
DateTime now;
DateTime PowerOn;
byte LastRead, ResetVals;
unsigned long old_ts = 0;
float PressureHistory [20] = {
700, 700, 700, 700, 700,
700, 700, 700, 700, 700,
700, 700, 700, 700, 700,
700, 700, 700, 700, 700
};
float HumHistory [20] = {
700, 700, 700, 700, 700,
700, 700, 700, 700, 700,
700, 700, 700, 700, 700,
700, 700, 700, 700, 700
};
float TempHistoryIn [20] = {
-127, -127, -127, -127, -127,
-127, -127, -127, -127, -127,
-127, -127, -127, -127, -127,
-127, -127, -127, -127, -127
};
float TempHistoryOut [20] = {
30, 40, 42, 39, 38,
10, 40, 42, 39, 38,
-1, 40, 42, 39, 38,
30, 40, 42, 39, 38
};
//OutTemp
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 8
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
//Chars for graph
byte ArrCharIndex[9] = {
254, 2, 95, 3, 4, 176, 5, 6, 7
};
//Zambretty array
const byte Zarr[32] PROGMEM =
{ 0,//a
1,//b
3,//d
7,//h
14,//o
17,//r
20,//u
21,//v
23,//x
0,//a
1,//b
4,//e
10,//k
13,//n
15,//p
18,//s
22,//w
23,//x
25,//z
0,//a
1,//b
2,//c
5,//f
6,//g
8,//i
9,//j
11,//l
12,//m
16,//q
19,//t
24,//y
25//z
};
const char string_0[] PROGMEM = "Settled fine";//0
const char string_1[] PROGMEM = "Fine weather";//0
const char string_2[] PROGMEM = "Becaming fine";//0
const char string_3[] PROGMEM = "Fine, becoming less settled";//0
const char string_4[] PROGMEM = "Fine, possible showers";//0
const char string_5[] PROGMEM = "Fairly fine, improving";//0
const char string_6[] PROGMEM = "Fairly fine, possible showers early";//0
const char string_7[] PROGMEM = "Fairly fine, showery later";//0
const char string_8[] PROGMEM = "Showery early, improving";//0
const char string_9[] PROGMEM = "Changeable, mending";//0
const char string_10[] PROGMEM = "Fairly fine, showers likely";//0
const char string_11[] PROGMEM = "Rather unsettled clearing later";//0
const char string_12[] PROGMEM = "Unsettled, probably improving";//0
const char string_13[] PROGMEM = "Showery, bright intervals";//0
const char string_14[] PROGMEM = "Showery, becoming less settled";//0
const char string_15[] PROGMEM = "Changeable, some rain";//0
const char string_16[] PROGMEM = "Unsettled, short fine intervals";//0
const char string_17[] PROGMEM = "Unsettled, rain later";//0
const char string_18[] PROGMEM = "Unsettled, some rain";//0
const char string_19[] PROGMEM = "Mostly very unsettled";//0
const char string_20[] PROGMEM = "Occasional rain, worsening";//0
const char string_21[] PROGMEM = "Rain at times, very unsettled";//0
const char string_22[] PROGMEM = "Rain at frequent intervals";//0
const char string_23[] PROGMEM = "Rain, very unsettled";//0
const char string_24[] PROGMEM = "Stormy, may improve";//0
const char string_25[] PROGMEM = "Stormy, much rain";//0
const char* const string_table[] PROGMEM = {
string_0,
string_1,
string_2,
string_3,
string_4,
string_5,
string_6,
string_7,
string_8,
string_9,
string_10,
string_11,
string_12,
string_13,
string_14,
string_15,
string_16,
string_17,
string_18,
string_19,
string_20,
string_21,
string_22,
string_23,
string_24,
string_25
};
//hum icon
const byte HumCHR[8] = {
B00100,
B00100,
B01010,
B01010,
B10001,
B10001,
B10001,
B01110
};
//temp icon
const byte Temp[8] = {
B00100,
B01010,
B01010,
B01110,
B01110,
B11111,
B11111,
B01110
};
//graph char 1/8
const byte ch1[8] = {
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B11111
};
//graph char 2/8 is _ char
//graph char 3/8
const byte ch3[8] = {
B00000,
B00000,
B00000,
B00000,
B00000,
B11111,
B00000,
B00000
};
//graph chars 4/8
const byte ch4[8] = {
B00000,
B00000,
B00000,
B00000,
B11111,
B00000,
B00000,
B00000
};
//graph char 5/8 is - char
//graph chars 6/8
const byte ch6[8] = {
B00000,
B00000,
B11111,
B00000,
B00000,
B00000,
B00000,
B00000
};
//graph char 7/8
const byte ch7[8] = {
B00000,
B11111,
B00000,
B00000,
B00000,
B00000,
B00000
};
//graph char 8/8
const byte ch8[8] = {
B11111,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000
};
int scroll = 0;
char buffer [33];
byte UpDownStable = 0;
int UserAltitude;
void setup ()
{
pinMode(3, OUTPUT);
pinMode(BTN, INPUT_PULLUP);
pinMode(BTNUP, INPUT_PULLUP);
pinMode(BTNDOWN, INPUT_PULLUP);
Wire.begin();
Wire.beginTransmission(0x27);
lcd.begin(20, 4); // initialize the lcd
//load custom chars
// lcd.setBacklight(255);
lcd.createChar (0, Temp);
lcd.createChar (1, HumCHR);
lcd.createChar (2, ch1);
lcd.createChar (3, ch3);
lcd.createChar (4, ch4);
lcd.createChar (5, ch6);
lcd.createChar (6, ch7);
lcd.createChar (7, ch8);
//must be called after loading chars
lcd.home();
lcd.clear();
while (!bme.begin()) {
lcd.clear();
lcd.print("PrSensorError");
}
while (!rtc.begin()) {
lcd.clear();
lcd.print("ClockError");
}
// SetBrightness(brightness);
tm1637.init();
tm1637.set(7);
//Высота над уровнем моря
UserAltitude = EEPROMReadInt(0);
//just read data from sensors. ds18d20 sometimes in first 1-2 read return 85.0C
while(OutT==85)
readSensors(rtc.now(), true, false);
PowerOn = rtc.now();
LastRead = rtc.now().hour();
ResetVals = rtc.now().date();
//store first values from sensors to limit values
readSensors(rtc.now(), true, true);
//save current values from the sensors to history
//for normal graph view in first 20 hours of work
for (int tt = 0; tt < 20; tt++)
{
PressureHistory[tt] = Pres;
TempHistoryIn[tt] = InT;
TempHistoryOut[tt] = OutT;
HumHistory[tt]=Hum;
}
//show main screen by default
DisplayMode = 1;
//try to forecast =)
Forecast(now.month());
Serial.begin(9600);
}
void loop ()
{
//return to main screen from any other mode in 10 sec inactivity
if ( millis() - TimeReturn > 10000) {
if (DisplayMode != 1) {
lcd.clear();
lcd.home();
DisplayMode = 1;
}
TimeReturn = millis();
}
//main screen
if (DisplayMode == 1 ) {
now = rtc.now(); //get the current date-time
uint32_t ts = now.getEpoch();
//check second changed or not
if (old_ts != ts) {
scroll++;
old_ts = ts;
//Write time on tm1367
tm1637.display(0, now.hour() / 10);
tm1637.display(1, now.hour() % 10);
tm1637.display(2, now.minute() / 10);
tm1637.display(3, now.minute() % 10);
//blink dot
tm1637.point(ts % 2 == 0 ? POINT_OFF : POINT_ON);
//write current time and date on 20*4
WriteTimeDT(now, 0, 0,false);
WriteDateDT(now, 6, 0);
//if hour changes store current sensor values to history
if (LastRead != now.hour())
{
LastRead = now.hour();
readSensors(rtc.now(), true, true);
for (byte i = 0; i < 19; i++) {
PressureHistory[i] = PressureHistory[i + 1];
TempHistoryIn[i] = TempHistoryIn[i + 1];
TempHistoryOut[i] = TempHistoryOut[i + 1];
HumHistory[i]=HumHistory[i+1];
}
TempHistoryIn[19] = InT;
TempHistoryOut[19] = OutT;
PressureHistory[19] = Pres;
HumHistory[19]=Hum;
//if date changes reset limit values
if ( ResetVals != now.date()) {
ResetVals = now.date();
MaxTempO = -200;
MinTempO = 200;
MaxTempIn = -200;
MinTempIn = 200;
MaxPressure = 0;
MinPressure = 65000;
MaxHum = 0;
MinHum = 101;
readSensors(rtc.now(), true, true);
}
}
//read sensors values
//each sensor interrogated 1 time per 60 seconds
//and 20 seconds delay between different sensors
if (now.second() % 10 == 0 && now.second() > 0)
{
SetBrightness(analogRead(1));
readSensors(now, false, true);
lcd.setCursor(0, 3);
lcd.print(" ");
lcd.setCursor(0, 3);
//try to forecast
//this function wrute on 4 line forecast
//lcd.print(Forecast(now.month()));
Forecast(now.month());
//serial write some data
Serial.print("<h");
Serial.print(now.hour());
Serial.print("m");
Serial.print(now.minute());
Serial.print("s");
Serial.print(now.second());
Serial.print("D");
Serial.print(now.date());
Serial.print("M");
Serial.print(now.month());
Serial.print("Y");
Serial.print(now.year());
Serial.print("d");
Serial.print(weekDay[now.dayOfWeek() - 1]);
Serial.print("InT");
Serial.print(InT);
Serial.print("Out");
Serial.print(OutT);
Serial.print("Hum");
Serial.print(Hum);
Serial.print("Pres");
Serial.print(Pres);
Serial.print("F-t");
Serial.print(buffer);
Serial.println(">");
}
}
//2 line
lcd.setCursor(0, 1);
//write in temp
lcd.print("In");
//write custom temp char
lcd.print(char(0));
lcd.print(InT);
//write out temp
lcd.print(" Out");
//write custom temp char
lcd.print(char(0));
lcd.print(OutT);
//3 line
lcd.setCursor(0, 2);
//write custom humidity char
lcd.print(char(1));
//write humidity
lcd.print(Hum);
lcd.print("% ");
lcd.print(Pres);
lcd.print("mmHg ");
scrollInFromRight(3, buffer);
}
//show limit waluea for out temp
if (DisplayMode == 2)
{
lcd.setCursor(0, 0);
lcd.print("Max out t");
WriteTimeDT(MaxTempOT, 0, 13,true);
lcd.setCursor(0, 1);
lcd.print(MaxTempO);
lcd.setCursor(0, 2);
lcd.print("Min out t");
WriteTimeDT(MinTempOT, 2, 13,true);
lcd.setCursor(0, 3);
lcd.print(MinTempO);
}
//draw graph for out temp
if (DisplayMode == 3)
{
lcd.setCursor(0, 0);
lcd.print("Out t hist");
drawGraphFullScreen(TempHistoryOut);
}
//show limit walues for in temp
if (DisplayMode == 4)
{
lcd.setCursor(0, 0);
lcd.print("Max in t");
WriteTimeDT(MaxTempInT, 0, 13,true);
lcd.setCursor(0, 1);
lcd.print(MaxTempIn);
lcd.setCursor(0, 2);
lcd.print("Min in t");
WriteTimeDT(MinTempInT, 2, 13,true);
lcd.setCursor(0, 3);
lcd.print(MinTempIn);
}
//draw graph for in temp
if (DisplayMode == 5)
{
lcd.setCursor(0, 0);
lcd.print("In t hist");
drawGraphFullScreen(TempHistoryIn);
}
//show limit walues for pressure
if (DisplayMode == 6)
{
lcd.setCursor(0, 0);
lcd.print("Max pressure");
WriteTimeDT(MaxPressureT, 0, 13,true);
lcd.setCursor(0, 1);
lcd.print(MaxPressure);
lcd.setCursor(0, 2);
lcd.print("Min pressure");
WriteTimeDT(MinPressureT, 2, 13,true);
lcd.setCursor(0, 3);
lcd.print(MinPressure);
}
//draw graph for pressure
if (DisplayMode == 7)
{
lcd.setCursor(0, 0);
lcd.print("Pressure hist");
drawGraphFullScreen(PressureHistory);
}
//show limit walues for humidity
if (DisplayMode == 8)
{
lcd.setCursor(0, 0);
lcd.print("Max humidity");
WriteTimeDT(MaxHumT, 0, 13,true);
lcd.setCursor(0, 1);
lcd.print(MaxHum);
lcd.setCursor(0, 2);
lcd.print("Min humidity");
WriteTimeDT(MinHumT, 2, 13,true);
lcd.setCursor(0, 3);
lcd.print(MinHum);
}
if (DisplayMode == 9)
{
lcd.setCursor(0, 0);
lcd.print("Humidity hist");
drawGraphFullScreen(HumHistory);
}
//show Altitude, uptime and (c)
if (DisplayMode == 10)
{
lcd.setCursor(0, 0);
lcd.print("Altitude ");
lcd.print(Altitude);
lcd.print("m ");
lcd.setCursor(0, 1);
lcd.print("PowerOn");
WriteTimeDT(PowerOn, 2, 0,true);
WriteDateDT(PowerOn, 6, 2);
lcd.setCursor(0, 3);
lcd.print("(c)IvanchenkoAV 2017");
}
//if button up pressed
if (!digitalRead(BTNUP) && DisplayMode < 100 && DisplayMode != 20)
{
DisplayMode++;
lcd.clear();
}
//if button down pressed
if (!digitalRead(BTNDOWN) && DisplayMode < 100 && DisplayMode != 20)
{
DisplayMode--;
lcd.clear();
}
if (!digitalRead(BTNUP) && !digitalRead(BTNDOWN) && DisplayMode < 100)
{
DisplayMode = 20;
lcd.clear();
}
if (DisplayMode == 20)
{
lcd.setCursor(0, 0);
lcd.print("Altitude ");
lcd.print(UserAltitude);
lcd.print("m");
lcd.setCursor(0, 1);
lcd.print("press Set to save");
if (!digitalRead(BTNUP))
UserAltitude++;
if (!digitalRead(BTNDOWN))
UserAltitude--;
if (!digitalRead(BTN))
{
EEPROMWriteInt(0, UserAltitude);
lcd.clear();
lcd.print("Saved");
delay(1000);
DisplayMode = 1;
}
if (UserAltitude > 800)
UserAltitude = 0;
if (UserAltitude < 0)
UserAltitude = 800;
}
//display menu limits
if (DisplayMode == 11)
{
DisplayMode = 1;
}
//display menu limits
if (DisplayMode == 0)
{
DisplayMode = 10;
}
//set button pressed
if (!digitalRead(BTN)) {
TimeReturn = millis();
//if set button pressed in main screen mode
if (DisplayMode < 100)
{
DisplayMode = 100;
//save current time to temp values
TempTime = rtc.now();
_h = TempTime.hour();
_m = TempTime.minute();
_day = TempTime.date();
_mon = TempTime.month();
_year = TempTime.year();
_week = TempTime.dayOfWeek();
}
else
//if button pressed in set mode
DisplayMode++;
//menu limit
if (DisplayMode == 107) {
lcd.setCursor(0, 1);
lcd.print("Cancel");
delay(3000);
DisplayMode = 1;
lcd.clear();
}
//delay(300);
}
delay(200);
//disp.set(brightness / 64 + 1);
//reset time return if any buton pressed
if (!digitalRead(BTNUP) || !digitalRead(BTNDOWN)) {
TimeReturn = millis();
}
//temp hour set
if (DisplayMode == 100)
{
if (!digitalRead(BTNUP))
_h++;
if (!digitalRead(BTNDOWN))
_h--;
if (_h > 23)
_h = 0;
if (_h < 0)
_h = 23;
lcd.clear();
lcd.home();
lcd.print("Hour ");
lcd.print(_h);
}
//temp minute set
if (DisplayMode == 101)
{
if (!digitalRead(BTNUP))
_m++;
if (!digitalRead(BTNDOWN))
_m--;
if (_m >= 60)
_m = 0;
if (_m < 0)
_m = 59;
lcd.clear();
lcd.home();
lcd.print("Minute ");
lcd.print(_m);
}
//temp date set
if (DisplayMode == 102)
{
if (!digitalRead(BTNUP))
_day++;
if (!digitalRead(BTNDOWN))
_day--;
if (_day > 31)
_day = 1;
if (_day < 1)
_day = 31;
lcd.clear();
lcd.home();
lcd.print("Day ");
lcd.print(_day);
}
//temp month set
if (DisplayMode == 103)
{
if (!digitalRead(BTNUP))
_mon++;
if (!digitalRead(BTNDOWN))
_mon--;
if (_mon > 12)
_mon = 1;
if (_mon < 1)
_mon = 12;
lcd.clear();
lcd.home();
lcd.print("Month ");
lcd.print(_mon);
}
//temp year set
if (DisplayMode == 104)
{
if (!digitalRead(BTNUP))
_year++;
if (!digitalRead(BTNDOWN))
_year--;
if (_year > 3000)
_year = 1;
if (_year < 1)
_year = 3000;
lcd.clear();
lcd.home();
lcd.print("Year ");
lcd.print(_year);
}
//temp weekday set
if (DisplayMode == 105)
{
if (!digitalRead(BTNUP))
_week++;
if (!digitalRead(BTNDOWN))
_week--;
if (_week > 7)
_week = 1;
if (_week < 1)
_week = 7;
lcd.clear();
lcd.home();
lcd.print("WeekDay ");
lcd.print(weekDay[_week - 1]);
}
// set new time?
if (DisplayMode == 106)
{
lcd.clear();
lcd.home();
lcd.print("Save Y/N?");
//if button up pressed save new time
if (!digitalRead(BTNUP))
{
DateTime dt(_year, _mon, _day, _h, _m, 0, _week);
rtc.setDateTime(dt);
lcd.setCursor(0, 1);
lcd.print("Ok");
delay(3000);
DisplayMode = 1;
lcd.clear();
}
//if button down pressed - exit to main screen
if (!digitalRead(BTNDOWN)) {
lcd.setCursor(0, 1);
lcd.print("Cancel");
delay(3000);
DisplayMode = 1;
lcd.clear();
}
}
}
//write time in x,y of lcd
void WriteTimeDT(DateTime Time, byte y, byte x,boolean dot) {
lcd.setCursor(x, y);
if (Time.hour() < 10)
lcd.print('0');
lcd.print(Time.hour());
lcd.print(Time.second() % 2 == 0||dot ? ':' : ' ');
if (Time.minute() < 10)
lcd.print('0');
lcd.print(Time.minute());
}
//write date in x,y of lcd
void WriteDateDT(DateTime Time, int x, int y) {
lcd.setCursor(x, y);
if (Time.date() < 10)
lcd.print('0');
lcd.print(Time.date());
lcd.print('/');
if (Time.month() < 10)
lcd.print('0');
lcd.print(Time.month());
lcd.print('/');
lcd.print(Time.year());
lcd.print(' ');
lcd.print(weekDay[Time.dayOfWeek() - 1]);
}
//draw graph
void drawGraphFullScreen(float x[20]) {
//
float maxp = -30000, minp = 30000;
float divider;
byte curVal;
//saerch max and min values in history
for (byte i = 0; i < 20; i++)
{
if ( x[i] > maxp)
maxp = x[i];
if ( x[i] < minp)
minp = x[i];
}
//graph draw in 3 lines, so we have 24 pixels height graph
//Do not deny yourself anything =)
// divider - value of division of 1 pixel +0.01 to prevert division by 0
divider = (maxp - minp) / 24 + 0.01;
//write value of division
lcd.setCursor(14, 0);
lcd.print(divider);
for (byte i = 0; i < 20; i++)
{
//draw 4 line, bottom of graph
curVal = byte((x[i] - minp) / divider);
lcd.setCursor(i, 3);
//if current value of graph catch in value 0 to 8*divider
//we draw chart
if (curVal <= 8)
{
//seach appropriate char in array of custom chars
if (curVal > 0)
lcd.print(char(ArrCharIndex[curVal]));
else
//if current val = min
lcd.print(char(2));
}
else
//if chart line upper than current line print blank char
lcd.print(char(ArrCharIndex[0]));
//draw 3 line - middle of graph
lcd.setCursor(i, 2);
if (curVal <= 16 && curVal > 8)
//if current value of graph catch in value 8*divider to 16*divider
//we draw chart
//seach appropriate char in array of custom chars
lcd.print(char(ArrCharIndex[curVal - 8]));
else
//if chart line upper or lover than current line print blank char
lcd.print(char(ArrCharIndex[0]));
lcd.setCursor(i, 1);
//draw 4 line, bottom of graph
if (curVal <= 24 && curVal > 16)
//if current value of graph catch in value 16*divider to 24*divider
lcd.print(char(ArrCharIndex[curVal - 16]));
else
//if chart line lover than current line print blank char
lcd.print(char(ArrCharIndex[0]));
}
}
//read data from sensors depending on currend second
//bool Now means read all data immideatly
//bool store mean save limiting values data or not
void readSensors (DateTime Time, boolean Now, boolean store)
{
if (!Now) {
switch ( Time.second()) {
case 20:
//out temp dht18d20
sensors.requestTemperatures();
OutT = sensors.getTempCByIndex(0);
//store limiting values and time when they arrived
if (store) {
if (OutT > MaxTempO) {
MaxTempO = OutT;
MaxTempOT = Time;
}
if (OutT < MinTempO) {
MinTempO = OutT;
MinTempOT = Time;
}
}
break;
case 30:
dht11.read(pinDHT11, &DHT11temperature, &Hum, NULL);
//store limiting values and time when they arrived
if (store) {
if (Hum > MaxHum) {
MaxHum = Hum;
MaxHumT = Time;
}
if (Hum < MinHum) {
MinHum = Hum;
MinHumT = Time;
}
}
break;
case 40:
float hum(NAN);
uint8_t pressureUnit(0); // unit: B000 = Pa, B001 = hPa, B010 = Hg, B011 = atm, B100 = bar, B101 = torr, B110 = N/m^2, B111 = psi
bme.read(Pres, InT, hum, true, pressureUnit);
hPa = Pres / 100+ float(UserAltitude* 12.502 / 100);
Pres = Pres * 0.00750063755419211;
Altitude = bme.alt(true);
//store limiting values and time when they arrived
if (store) {
if (Pres > MaxPressure) {
MaxPressure = Pres;
MaxPressureT = Time;
}
if (Pres < MinPressure) {
MinPressure = Pres;
MinPressureT = Time;
}
if (InT > MaxTempIn) {
MaxTempIn = InT;
MaxTempInT = Time;
}
if (InT < MinTempIn) {
MinTempIn = InT;
MinTempInT = Time;
}
}
break;
}
}
else {
if (store) {
}
//out temp dht18d20
sensors.requestTemperatures();
OutT = sensors.getTempCByIndex(0);
//read humidity
dht11.read(pinDHT11, &DHT11temperature, &Hum, NULL);
//reap pressure and temp
float hum(NAN);
uint8_t pressureUnit(0); // unit: B000 = Pa, B001 = hPa, B010 = Hg, B011 = atm, B100 = bar, B101 = torr, B110 = N/m^2, B111 = psi
bme.read(Pres, InT, hum, true, pressureUnit);
hPa = Pres / 100+ float(UserAltitude* 12.502 / 100) ;
//convert hPa to mmHh
Pres = Pres * 0.00750063755419211;
Altitude = bme.alt(true);
//store limiting values and time when they arrived
if (store) {
if (Pres > MaxPressure) {
MaxPressure = Pres;
MaxPressureT = Time;
}
if (Pres < MinPressure) {
MinPressure = Pres;
MinPressureT = Time;
}
if (InT > MaxTempIn) {
MaxTempIn = InT;
MaxTempInT = Time;
}
if (InT < MinTempIn) {
MinTempIn = InT;
MinTempInT = Time;
}
if (Hum > MaxHum) {
MaxHum = Hum;
MaxHumT = Time;
}
if (Hum < MinHum) {
MinHum = Hum;
MinHumT = Time;
}
if (OutT > MaxTempO) {
MaxTempO = OutT;
MaxTempOT = Time;
}
if (OutT < MinTempO) {
MinTempO = OutT;
MinTempOT = Time;
}
}
}
}
// Select weather index Zambretti
byte Forecast(byte Mon)
{
float z = 0;
char a;
//Pressure is up
if ((PressureHistory[19] >= PressureHistory[18] || PressureHistory[18] >= PressureHistory[17] ) && (PressureHistory[19] - PressureHistory[17] > 0.3 || PressureHistory[19] - PressureHistory[16] > 0.2))
{
z = 179 - 2 * hPa / 12.9;
if (Mon >= 5 && Mon <= 9)
z -= 2;
if (Mon < 5 || Mon > 9)
z -= 1;
strcpy_P(buffer, (char*)pgm_read_word(&(string_table[pgm_read_byte(&Zarr[int(z)])])));
UpDownStable = 1;
}
else
// Pressure is down
if ((PressureHistory[19] - PressureHistory[17] <= -0.3 || PressureHistory[19] - PressureHistory[16] <= -0.2) && ( PressureHistory[19] <= PressureHistory[18] || PressureHistory[18] <= PressureHistory[17]))
{
z = 130 - hPa / 8.1;
strcpy_P(buffer, (char*)pgm_read_word(&(string_table[pgm_read_byte(&Zarr[int(z)])])));
//return "-_" + ForecastText[Zarr[int(z)]];
if (Mon >= 5 && Mon <= 9)
z += 2;
if (Mon < 5 || Mon > 9)
z += 1;
UpDownStable = 2;
} else {
//stable pressure
z = 147 - 5 * hPa / 37.6;
strcpy_P(buffer, (char*)pgm_read_word(&(string_table[pgm_read_byte(&Zarr[int(z)])])));
UpDownStable = 3;
}
}
//write scroll text
void scrollInFromRight (byte line, char str1[]) {
String s = buffer;
byte len = strlen(str1);
lcd.setCursor(0, line);
//15 instead 20 to see, that line ends
if (len - scroll < 15)
scroll = 0;
lcd.print(s.substring(scroll, scroll + 20 > len ? len : scroll + 20));
if (len - scroll < 20)
lcd.print(" ");
}
void SetBrightness(int brightness)
{
analogWrite(3, constrain( map(brightness / 4, 0, 255, 70, 255), 70, 255));
}
void EEPROMWriteInt(int p_address, int p_value)
{
byte lowByte = ((p_value >> 0) & 0xFF);
byte highByte = ((p_value >> 8) & 0xFF);
EEPROM.write(p_address, lowByte);
EEPROM.write(p_address + 1, highByte);
}
//This function will read a 2 byte integer from the eeprom at the specified address and address + 1
unsigned int EEPROMReadInt(int p_address)
{
byte lowByte = EEPROM.read(p_address);
byte highByte = EEPROM.read(p_address + 1);
return ((lowByte << 0) & 0xFF) + ((highByte << 8) & 0xFF00);
}
Кстати, сейчас на eBay активно продаются аналоги (судя по маркировке) BMP280 и фейковые BME280 с прямоугольным а не квадратным чипом. В конце июня получил свой BMP280 датчик, так не смог заставить его работать ни по SPI ни по I2C. Продавец вернул деньги и только сегодня я заметил, что чип впаян вверх ногами. Сдул и перепаял - работает отлично. Обратите внимание, что отверстие чипа должно быть направлено к резисторам а не к конденсатору. На фото неправильно впаянный чип.
Всем доброго дня! Товарищи подскажите приобрел BME280 на али подключил по i2c первые показания выдает нормальные но секунд через 5 сваливаеться в крайние значения мин темпиратура -144 макс влажность 100 процентов и давление тож самое в чем может быть проблема?
В описании модуля в магазине написано "Поставка Напряжение: 1.8-5 В DC"
Подключено к питанию 3,3V Но пробовал и 5V давать ничего не меняется. Только я к модулю ESP12N подключаю без ардуины но думаю это не важно суть не в этом.
Ну, а такой вариант допустим: модуль с LDO (на что описание намекает), вы его в 3.3V суете, на датчике получаете 2.1, в лучшем случае. Любая просадка напряжения и сенсор клинит. На модуль посмотрите - есть там кроме самого сенсора трехногие и более детальки или нет.
Вроде есть. Если не сложно посмотрите детальку.... сылка
У BME, конечно, минимальное напряжение питание 1.2V заявлено, но черт его знает, что там за LDO. Я бы такой подключил к обычной 5V ардуине (и подключал вполне успешно) и посмотрел на поведение. Если будет работать устойчиво - значит, скорее всего, какие-то провалы по питанию при работе с ESP.
Да, именно о Вашем скетче. Он мне очень понравился, но компилятор что то не компилирует. Очень желаю вашу схему повторить. Больше, конечно, компилятор ругается на bme280i2c библиотеку. Поиски ведут в тупик.
Подскажите еще по подключению периферии к ардуино:
Дисплей lcd2004 с bme280 садится на а4/а5 (sdl/sda),
кнопки на d4...6,
Да,
dht11 садится на d9,
Ds18d20 садится на d8,
фоторезистор на пин a1
на i2c переходнике для дисплея снимается перемычка отвечающая за подсветку и на ногу, на которой нет потенциала относительно земли цепляется вывод d3 для управления яркостью. Но честно, плавное изменение делать не захотел (памяти не хватает уже) а без нее выглядит очень убого, потому в последней версии я автояркость отключил. Да и жене ночник хороший получился. =)
У меня есть предложение, я как доберусь домой, настрою эти библиотеки, и выложу настроенную среду сразу.
Обращаю внимание у меня еще подключен сегментный экран на d12 и d13
Содержимое заархивированной папки libraries\ распаковать в папку libraries\ в среде разработки и перезапустить.
Вроде библиотеки те же, завтра заберу с работы станцию попробую прошить.
Проблема была в том, что я писал используя версию от февраля 2017, а со последними версиями не компилируется.
Из замеченных багов за полгода:
*В строке 459 нужно добавить еще 1 пробел, стало заметно при минусовой температуре.
*константы определяющие динамику изменения погоды в функции byteForecast(byteMon)
(0,2 и 0,3) однозначно нужно увеличивать минимум в 2 раза, везде где встречаются. А вообще их нужно подбирать экспереминтально для вашего региона. У нас срань, а не погода в межсезонье.
Давление в течении дня на 5-8 мм прыгает за 2-3 часа, утром солнце и +15, в обед 0 и снежная крупа и легкий ветер нежно обрывает плитку со зданий и ласково прикладывает птичек к стенам домов и вечером снова ясно и +15. А зимой 4 месяца сракопада. Ну а летом датчик на солнце показывает до +60, а воздух прогревается до 35 и ниодного дождя за 4 месяца. Если где и приукрасил, то слегка, а кое где даже приуменьшил =)
Спасибо большое за помощь. Константы изменил, пробел добавил. На 2 компах компилировалось с ошибкой, на третьем пошло... Залил в ардуинку.Теперь проверить не могу. I2C дисплей не могу завести. Ничего не показывает.Будем тужиться завести на дисплей без I2C.
Спасибо большое за помощь. Константы изменил, пробел добавил. На 2 компах компилировалось с ошибкой, на третьем пошло... Залил в ардуинку.Теперь проверить не могу. I2C дисплей не могу завести. Ничего не показывает.Будем тужиться завести на дисплей без I2C.
Виктор Николаевич, не пробовал.Это идея. Заливал тестовый скетч из библиотеки liquid cristal pf8574. Загружал - в мониторе порта была какая то кракозября и не более того.О том, что нету дисплея - порт не сообщал
Сканер показал 0x3f. Как всегда, или лодка дырявая или акула глухая
В оригинале: LiquidCrystal_PCF8574 lcd(0x27)
Придется просить компилировать с вашим 0x3f. Потому как PCF8574A не переключится на 0x3F, насколько я помню. А, судя по адресу, именно он у вас, а не обычный простой PCF8574 без индекса.
Всем спрасибо за помощь. Проект пошел, только почему то атмосферное давление и другие параметры не обновляются автоматически. В скетче заменил адрес. Все показывает. Подсветка не работает, хоть и закинул на в3.но это мелочи.Проект начал хоть что то показывать.
Всем спрасибо за помощь. Проект пошел, только почему то атмосферное давление и другие параметры не обновляются автоматически. В скетче заменил адрес. Все показывает. Подсветка не работает, хоть и закинул на в3.но это мелочи.Проект начал хоть что то показывать.
Все показания с датчиков обновляются раз в минуту. Каждые 20 секунд обновляется значение 1 из датчиков. Чаще просто не вижу смысла, температура, давление и влажность крайне инертные велечины.
Она устанавливает значение PWM от 70 до 255 на пине 3 в зависимости от напряжения на входе А1. Этот вход замеряет напряжение на делителе 10кОм+фоторезистор. Маркировка последнего неизвестна, но эксперементально он меняет сопротивление примерно от 4кОм до 12кОм.
Нет, пока есть пара проблем в железе и огромная проблема со временем - внук у меня родился. Много времени уходит на помощь дочери (в поликлиннику свозить, документы оформить, прописать в квартире и т.д.) А с железом вот какая проблема. Было все собрано на DIP ATMega 328, на макетке. В нее сразу залил загрузчик с Ардуины 3-х вольтовой и потом скетч. Сначала все работало нормально, потом изображение на индикаторе пропало. Ресет не помог. Выключил - оставил так. Через пару часов включил, все работает. Потом снова все отключается. Закономерности по времени никакой нет, может и трое суток проработать, может через час выключиться. И на включение похожая ситуация, может сразу включиться, а может только через сутки. Не пойму. Хотя есть догадка - кварц на меге поставил тот который был - на 12 МГц, а нужен на 8. Может по этому через время срывается генерация...?
Я для narodmon.ru буду делать на Wemos D1, жду датчики, едут два BMP-280, DS18B20 у меня россыпью штук 50 есть, еще едут DS3231 и еще какие-то, на HMC5883L хотел флюгер сделать, но думаю проще будет на энкодере 360 градусов, но он по цене кусается 1500= )))
Я поколдую с твоим скетчем, запущу под I2C, скину здесь
Вот болванка под I2C, датчики не ставил, дисплей работает )))
Компилировал под 1.6.12 но некоторые библиотеки из под старых версий ставят систему в позу, подправил пути для файлов библиотек
Ты BMP-280 к чему и как подключаешь?
У меня он не заработал, видимо брак, ни по I2C - ни по SPI-SOFT
Это заработавший скетч на библиотеке "SparkFun_BME280" - сокращёный пример, но есть несколько "но".
У меня он не заработал, видимо брак, ни по I2C - ни по SPI-SOFT
не знаю как тут вставлять картинки.
1. умножить на коэффициент (ртуть в 13 с гаком раз тяжелее воды к примеру) или напрямую к примеру 1000 гектопаскалей это 750 мм ртутного столба
2. А через String?
Привет всем. Когдо сам занимался этой темой перепробывал много библиотек. И с уверенностью могу отметить, что самая оптимальная, для меня, оказалась библиотека - "cactus_io_BME280_I2C.h"
Привет всем. Когдо сам занимался этой темой перепробывал много библиотек. И с уверенностью могу отметить, что самая оптимальная, для меня, оказалась библиотека - "cactus_io_BME280_I2C.h"
Отсюда?
Да.
У меня он не заработал, видимо брак, ни по I2C - ни по SPI-SOFT
не знаю как тут вставлять картинки.
Картинки вставлять просто, нажимаешь кнопку изображение, далее кнопку выбор на сервере, потом загрузить, потом вставить и всё
Получил китайский BMP-280, но настроить пока не получается.
Распиновка:
SCL - 13
SDA - 11
CSB - 10
SDO - 12
Запустил Adafruit'овский тестовый скетч. Библиотека естественно от Adafruit, но в архиве не было файла Adafruit_Sensor.h. Докачал откуда то, тоже вроде с github.
Из этого можно увидеть что на первом результате температура правильная, а вот давление и высота над уровнем моря вообще не то.
А на втором результате температура очень завышена, давление более менее нормальная, высота тоже не ахти но уже тоже более менее близка к правде.
Потом запаял ножки к датчику и тогда получаю только результаты ближе к №2.
Temp = 41.76 *C
Pressure = 723.45 mm.rt.st
~Height = 415.29 m
если датчик меняет значения адекватно, то просто в скетче сделайте вот так
это я подогнал показания bme280 под показания домашней метеостанции орегон. а вы можете в своей местности посмотреть на народмон и также подкорректировать показания
Всем привет, вчера закончил программу для своей погодной станции. Пока гуглил по датчику BMP280 натыкался на эту ветку форума.
У меня возникло одно замечание, для всех ваших скетчей, вы слишком часто опрашиваете датчики, у меня, когда я опрашиваю чаще чем 5-10 секунд, медленно но заметно начинает повышатся температура DHT3231 и DS18D20. За BMP280 такой беды не замеченно, но на всякий случай я опрашиваю датчики 1 раз в минуту.
Я собрал станцию (пока на макетке) на часах DHT3231, внешнем датчике температуры DS18D20, барометр BMP280, экран 20*4 I2C, гигрометр DHT-11 (знаю, гадость, но у нас из-за боевых действий другие купить проблематично) и 7 сегментный дисплей на TM1637 чтобы было издалека видно время.
Погодная станция прогнозирует изменение погоды по алгоритму Zambretti, основываясь на динамике изменения давления за последние 3 часа. Может строить график изменения давления, температуры внутри и снаружи за последние 20 часов. Запоминает время достижения минимального и максимального значения 2 температур, влажности и давления за эти сутки. Выводит основные показатели на COM порт. Возможность выставлять время, дату и день недели кнопками. На остальное не хватило памяти. Скорее всего, как разбогатею, куплю еще 1 микроконтроллер, на него повешу опрос всех датчиков и экраны и буду передавать через COM порт на 2-й МК, в котором будут обрабатываться данные, и прочие плюшки =)
Комменты на английском, мне так легче, ненавижу язык переключать =)
Фото основного экрана
еще фото
/sites/default/files/u29096/img_2017-05-26_123030_hdr.jpg
/sites/default/files/u29096/img_2017-05-26_123033_hdr.jpg
/sites/default/files/u29096/img_2017-05-26_123041_hdr.jpg
/sites/default/files/u29096/img_2017-05-26_123045_hdr.jpg
/sites/default/files/u29096/img_2017-05-26_123051_hdr.jpg
/sites/default/files/u29096/img_2017-05-26_123058_hdr.jpg
/sites/default/files/u29096/img_2017-05-26_123051_hdr_0.jpg
/sites/default/files/u29096/img_2017-05-26_123105_hdr.jpg
/sites/default/files/u29096/img_2017-05-26_123124_hdr.jpg
фоткать меню выставления времени не стал )
Красиво получилось
Красиво получилось
Что красивового то? Красиво - это когда черным по белому и понятным родным языком написано! :-)
Хотя бы вот так -
Красиво получилось
Что красивового то? Красиво - это когда черным по белому и понятным родным языком написано! :-)
так напишите, весь код выложен, вам надо вам и флаг в руки, мне лично безразлично, на каком из европейских языков написано
К коду замечания есть? есть - свой код в студию, посозерцаем на ваши шедевры
Лично я лучшей математики в реализации метеостанции не видел, носом ткните если знаете, что такое есть
Что красивового то? Красиво - это когда черным по белому и понятным родным языком написано! :-)
Как война закончится (надеюсь когда-нибудь это случится), куплю нормальный экран с поддержкой кирилицы, а не выдранный из неведомой хрени на барахолке и корейским шрифтом.
И как уже говорилось выше, если у вас экран это поддерживает, замените в исходнике текст, дело 5 минут. А тратить драгоценную память переменных под русские буквы, для меня непозволительно. И так думаю уже о объединении 2 МК в одном устройстве, для освобождения ресурсов. Один чисто как хранилище данных использовать. Кстати, в данном виде, если вы проведете русификацию, у вас не загрузится прошивка, не хватит бамяти. В этом коде если использовать еще 42 байта памяти переменных программа начинает работать нестабильно, из-за нехватки памяти. Тут каждая команда выверена и 3 раза оценена именно с точки зрения уменьшения объема кода. Я пробовал разные варианты одного и того же, и выбирал самый легковесный. В планах еще поковырять библиотеки, возможно там есть за счет чего освободить память.
Лично для меня основная фишка прибора - именно прогноз. Я на непосредственно программу потратил от силы 5-6 часов. С подключением устройств и долбежкой с библиотеками. И примерно 20 часов искал в интернете что то вменяемое, что можно запрограммировать.
И второй фишкой является то, что на приборе можно выставлять время без сторонних примочек.
Сейчас буду пытаться подключить к программатору эту плату, надеюсь мне очень очень повезет и эта штука окажется рабочей, несмотря на то, что в плату явно попало 220.
Нашел на барахолке, не знаю что это, но явно втыкалось в комп.
Если заработает, я спасен и я смогу сделать еще кучу хотелок.
В планах, если заработает:
*Внести все варианты ветвления прогноза калькулятора Zambretti без обобщений и сокращений, с плавной прокруткой длинных строк, что то типа бегущей строки но 1-й;
*График изменения влажности (не хватило памяти);
*Графики с заполнением, а не черточки как сейчас. И шаг графиков 6 минут, вместо 1 часа, получается очень красиво красиво, но сейчас не хватает памяти даже для 1 параметра;
*Автоматическая плавная яркость 2 экранов;
*Будильник;
*RGB Подсветка с плавным переходом оттенков в зависимости от внешней t. (холодно - синий, по мере потепления - желтый, зона комфорта - зеленый, жарко - красный;
*Внешние радио датчики температуры, влажности, освещенности и т.п. связуемые через 433мГц передатчик;
*Датчик солнечной радиации;
*Счетчик Гейгера (уже готов, собран на другом МК, но на погодной станции не хватает памяти, чтобы получать данные с него). Планировал подключение через 433мГц пердатчик, чтобы счетчик Гейгера был автономным самсодостаточным устройством, но если окажется включенным в зоне погодной станции, чтобы она автоматом тянула с него показания.
Все это можно сделать за пару часов, но... Где бы мне купить Мегу 256 по цене как на Али, а не за 4700 рублей как у нас. =)
ЗЫ мне отчасти английский даже понятнее, жене - всеравно, мелкому пока вообще всеравно какая погода, время суток и температура)
ЗЫЫ а кто сказал, что для меня русский - родной ;)
AD73360 однозначно вжаренная, шесть 16 битных ацп
_zerabot_, не принимайте все близко к сердцу. Извините, если обидел. Главное, Вы достигли цели, Вас это устраевает, а остальное .... .
>>Genri5 Да какие обиды. Просто у каждого свои вкусы и фломастеры на вкус и цвет разные )
>>ua6em Меня на плате интересует Мега 128, там есть где разгуляться в плане ресурсов. Кстати, сейчас гуглил по вопросу нехватки памяти, возможно я нашел выход. Нашел код, который позволяет хранить строковые данные в области памяти программы. А у меня там около 8 кб свободно еще, такчто возможно живем еще.
Если кто то хочет пострадать с прогнозом погоды http://monatkodenis.blogspot.com/2016/09/zambretti-3.html
Алгоритм брал отсюда. Лучше алгоритм можете не искать, т.к. похоже инфа по прогнозированию погоды является чуть ли не достоянием нации и не подлежит широкой огласке. Сведения о прогнозировании очень туманны и слабо поддаются систематизации.
На данный момент окончательный код, до сборки в железе больше изменений не планирую.
По сравнению с предыдущим вариантом добавлено:
* Автояркость на основании аналогового фоторезистора
* Меню для пользовательского выставления высоты, вызывается одновременным нажатием кнопок + и -, изменение ими же, сохранение - кнопка Set.
* Реализованны все ветвления калькулятора Zambretti в оригинальном виде без изменений.
* Уменьшенны пороги определения динамики изменения погоды. Теперь считается, что давление падает или растет если изменилось на 0.2 мм за 3 часа или 0.3 мм за 4 часа.
* Исправленна ошибка размерности, при приведении давления к уровню моря в прогнозе прибавлял mmHg к hPa.
* Все массивы использующиеся в прогнозировании объявленны константами и закинуты в память программы. Таким образом, несмотря на значительное добавление записей в эти массивы освободил около 180 байт памяти переменных.
* Косметические изменения функции вывода времени (на основном экране точки мигают, на остальных экранах всегда отображаются статично)
* Автопрокрутка длинных строк для прогноза.
* Приделан костыль для датчика 18d20, который 50/50 при первых 1-2 замерах показывает температуру 85.0, после работает стабильно неделями. Уже не первый раз сталкиваюсь.
* Почасовой график влажности.
Кстати, сейчас на eBay активно продаются аналоги (судя по маркировке) BMP280 и фейковые BME280 с прямоугольным а не квадратным чипом. В конце июня получил свой BMP280 датчик, так не смог заставить его работать ни по SPI ни по I2C. Продавец вернул деньги и только сегодня я заметил, что чип впаян вверх ногами. Сдул и перепаял - работает отлично. Обратите внимание, что отверстие чипа должно быть направлено к резисторам а не к конденсатору. На фото неправильно впаянный чип.
у меня получилось вот это...
Всем доброго дня! Товарищи подскажите приобрел BME280 на али подключил по i2c первые показания выдает нормальные но секунд через 5 сваливаеться в крайние значения мин темпиратура -144 макс влажность 100 процентов и давление тож самое в чем может быть проблема?
попрубуй посадить cs на 3,3v
На али есть BMP280 с level converter + ldo для работы с 5V МК, а есть чисто 3.3v. Вы там не втыкаете в 5V ардуину "облегченный" модуль?
В описании модуля в магазине написано "Поставка Напряжение: 1.8-5 В DC"
Подключено к питанию 3,3V Но пробовал и 5V давать ничего не меняется. Только я к модулю ESP12N подключаю без ардуины но думаю это не важно суть не в этом.
Ну, а такой вариант допустим: модуль с LDO (на что описание намекает), вы его в 3.3V суете, на датчике получаете 2.1, в лучшем случае. Любая просадка напряжения и сенсор клинит. На модуль посмотрите - есть там кроме самого сенсора трехногие и более детальки или нет.
Вроде есть. Если не сложно посмотрите детальку.... сылка
Вроде есть. Если не сложно посмотрите детальку.... сылка
У BME, конечно, минимальное напряжение питание 1.2V заявлено, но черт его знает, что там за LDO. Я бы такой подключил к обычной 5V ардуине (и подключал вполне успешно) и посмотрел на поведение. Если будет работать устойчиво - значит, скорее всего, какие-то провалы по питанию при работе с ESP.
Спасибо! Попробую так сделать.
Пытаюсь скомпилировать скетч - выдает море ошибок.
Посему вопрос: какие у Вас библиотеки стоят?
Не компилируется скетч. Выдает кучу ошибок. Библиотеки качал с Гита. В чем может быть проблема?
если речь о моем скетче то у меня используется http://www.mathertel.de/Arduino/LiquidCrystal_PCF8574.aspx
Она отилчно ищется в подключении библиотек по фразе LiquidCrystal_PCF8574.
Обращаю внимание, что у меня экран подключен через i2c адаптер.
Да, именно о Вашем скетче. Он мне очень понравился, но компилятор что то не компилирует. Очень желаю вашу схему повторить. Больше, конечно, компилятор ругается на bme280i2c библиотеку. Поиски ведут в тупик.
Библиотека отсюда. https://github.com/finitespace/BME280 Инсталится ручками.
Это кстати единственная библиотека, которая на моем китайском клоне выдает результаты похожие на правду.
PS у меня версия arduino 1.8.2
Библиотека отсюда. https://github.com/finitespace/BME280 Инсталится ручками.
Это кстати единственная библиотека, которая на моем китайском клоне выдает результаты похожие на правду.
PS у меня версия arduino 1.8.2
А чем хуже : "cactus_io_BME280_I2C.h" ?
Кто может скомпилировать скетч _zerabot_ из поста #120 под nano v3 и выложит здесь?
Кто может скомпилировать скетч _zerabot_ из поста #120 под nano v3 и выложит здесь?
После работы сделаю.
Обращаю внимание у меня еще подключен сегментный экран на d12 и d13
0029
//LedDisplay
0030
#include "TM1637.h" // Подключаем библиотеку
0031
#define CLK 13 // К этому пину подключаем CLK
0032
#define DIO 12 // К этому пину подключаем DIO
0033
TM1637 tm1637(CLK, DIO);
Конечно, буду ждать.Премного буду благодарен.
Только пока у меня TM1637 нет. Буду покупать.
Вот ссылка на архив с библиотеками. https://cloud.mail.ru/public/L4vX/UFrvfkHat
Содержимое заархивированной папки libraries\ распаковать в папку libraries\ в среде разработки и перезапустить.
Вроде библиотеки те же, завтра заберу с работы станцию попробую прошить.
Проблема была в том, что я писал используя версию от февраля 2017, а со последними версиями не компилируется.
Из замеченных багов за полгода:
*В строке 459 нужно добавить еще 1 пробел, стало заметно при минусовой температуре.
*константы определяющие динамику изменения погоды в функции
byte
Forecast(
byte
Mon)
(0,2 и 0,3) однозначно нужно увеличивать минимум в 2 раза, везде где встречаются. А вообще их нужно подбирать экспереминтально для вашего региона. У нас срань, а не погода в межсезонье.
Давление в течении дня на 5-8 мм прыгает за 2-3 часа, утром солнце и +15, в обед 0 и снежная крупа и легкий ветер нежно обрывает плитку со зданий и ласково прикладывает птичек к стенам домов и вечером снова ясно и +15. А зимой 4 месяца сракопада. Ну а летом датчик на солнце показывает до +60, а воздух прогревается до 35 и ниодного дождя за 4 месяца. Если где и приукрасил, то слегка, а кое где даже приуменьшил =)
Спасибо большое за помощь. Константы изменил, пробел добавил. На 2 компах компилировалось с ошибкой, на третьем пошло... Залил в ардуинку.Теперь проверить не могу. I2C дисплей не могу завести. Ничего не показывает.Будем тужиться завести на дисплей без I2C.
Спасибо большое за помощь. Константы изменил, пробел добавил. На 2 компах компилировалось с ошибкой, на третьем пошло... Залил в ардуинку.Теперь проверить не могу. I2C дисплей не могу завести. Ничего не показывает.Будем тужиться завести на дисплей без I2C.
а сканер I2C дисплей находит?
Виктор Николаевич, не пробовал.Это идея. Заливал тестовый скетч из библиотеки liquid cristal pf8574. Загружал - в мониторе порта была какая то кракозября и не более того.О том, что нету дисплея - порт не сообщал
Сканер показал 0x3f. Как всегда, или лодка дырявая или акула глухая
Сканер показал 0x3f. Как всегда, или лодка дырявая или акула глухая
В оригинале: LiquidCrystal_PCF8574 lcd(0x27)
Придется просить компилировать с вашим 0x3f. Потому как PCF8574A не переключится на 0x3F, насколько я помню. А, судя по адресу, именно он у вас, а не обычный простой PCF8574 без индекса.
Всем спрасибо за помощь. Проект пошел, только почему то атмосферное давление и другие параметры не обновляются автоматически. В скетче заменил адрес. Все показывает. Подсветка не работает, хоть и закинул на в3.но это мелочи.Проект начал хоть что то показывать.
Всем спрасибо за помощь. Проект пошел, только почему то атмосферное давление и другие параметры не обновляются автоматически. В скетче заменил адрес. Все показывает. Подсветка не работает, хоть и закинул на в3.но это мелочи.Проект начал хоть что то показывать.
Все показания с датчиков обновляются раз в минуту. Каждые 20 секунд обновляется значение 1 из датчиков. Чаще просто не вижу смысла, температура, давление и влажность крайне инертные велечины.
За установку яркости отвечает процедура
void
SetBrightness(
int
brightness)
1136
{
1137
1138
analogWrite(3, constrain( map(brightness / 4, 0, 255, 70, 255), 70, 255));
1139
}
Она устанавливает значение PWM от 70 до 255 на пине 3 в зависимости от напряжения на входе А1. Этот вход замеряет напряжение на делителе 10кОм+фоторезистор. Маркировка последнего неизвестна, но эксперементально он меняет сопротивление примерно от 4кОм до 12кОм.