Проблема в коде для метеостанции

bdbd_dbdb
Offline
Зарегистрирован: 23.12.2020

Здравствуйте! Просьба помочь с кодом для метеостанции. Он работает исправно, но в некоторых частях (продублированы внизу) почему-то не хочет работать по задумке. Вместо того, чтобы через определённый промежуток времени (t_pres) производить замер и сдвигать массив, после чего выводить последние 4 значения давления на дисплей, выводится только значение в левом краю дисплея (ячейка [3]), причём оно всегда равно нулевой ячейке массива. В самом начале работы станции также выводится только ячейка [3], тоже равная нулевой. Миллис поделён на тысячу, чтобы время было в секундах.

Немного не работает также функция Pressure, но там код похож, поэтому думаю, проблема там та же.

Код метеостанции:

//--------------БИБЛИОТЕКИ----------------
#include <Wire.h> // Библиотека для работы по i2c
#include <LiquidCrystal_I2C.h>// Библиотека для дисплея
#include <Adafruit_BMP280.h> // Библиотека для работы барометра
#include "DHT.h" // Библиотека для датчика влажности
#include "GyverPower.h" // Библиотека для пониженного энергопотребления
// --------------НАСТРОЙКИ----------------
const int16_t typedht = DHT22;// Тип датчика (DHT22, DHT11)
const int8_t zhdat = 30; // Время между замерами (в секундах), не более 255 секунд
const bool pres_sign = 1; // Показывать ли запись давления (0 - нет, 1 - да)
const int8_t zhdat_pres = 4; // Время показа данных с давлением (если в предыдущем пункте 1)
const uint16_t t_pres = 1800; // Раз во сколько замерять давление для вывода показаний на дисплей (если в предпредпоследнем пункте 1)
const bool prep_type = 1; // Тип подготовки системы (0 - лампочки вкл. по-очереди, 1 - лампочки все вкл., потом все выкл.)
const uint16_t zhdat_pogoda = 1800; // Раз во сколько замерять давление для предсказания погоды (в секундах)
//-------------ПЕРЕМЕННЫЕ-----------------
// Даём названия пинам датчиков:
#define mq A0 // Газов,
#define svet A1 // света,
#define vl 2 // влажности.
// Светодиоды:
#define r_rain 9 // РГБ осадков,
#define g_rain 8
#define b_rain 7
#define led A2 // Меняющий яркость от света светодиод,
#define lamp 10 // Лампочка, показывающая превышение нормы,
#define r 4 // РГБ газа.
#define g 5
#define b 6
// Переменные, хранящие показания датчиков:
int16_t pressure = 0; // Переменная давления,
int16_t gaz = 0; // Газов(газоанализатор),
int16_t temperature = 0;// Температуры,
int8_t h = 0; // Влажности,
int16_t altitude = 0; // Абсолютной высоты
int16_t weather [] = {0, 0}; // Массив для записи давления
int16_t pres [] = {111, 222, 333, 444}; // Массив для записи 2 давления
// Дополнительные переменные:
boolean lamp_indicator = 0; // Индикатор лампочки
int8_t gaz_b = 0; // Уровень газа(степень опасности),
int16_t dvl_b = 0; // Степень погоды для включения лампочек разного цвета
uint64_t pogoda_zapis = 0; // Переменная для записи времени последнего замера давления
uint64_t pres_zapis = 0; // Переменная для записи времени последнего замера 2 давления
LiquidCrystal_I2C lcd(0x27, 16, 2); // Установка дисплея
DHT dht(vl, typedht);// Настройка датчика влажности
Adafruit_BMP280 bmp280; // Настройка датчика давления
//------------SETUP--------------------
void setup() {
  lcd.init(); // Настройка дисплея
  lcd.backlight();// Включаем подсветку дисплея
  dht.begin(); // Подготовка датчика влажности
  while (!bmp280.begin(BMP280_ADDRESS - 1)) { // Подготовка датчика давления
    Serial.println(F("Could not find a valid BMP280 sensor, check wiring!"));
    delay(2000);
  }
  delay(100);
  pinMode(vl, INPUT); // Настраиваем пины
  pinMode(mq, INPUT);
  pinMode(svet, INPUT);
  pinMode(lamp, OUTPUT);
  pinMode(r, OUTPUT);
  pinMode(g, OUTPUT);
  pinMode(b, OUTPUT);
  pinMode(r_rain, OUTPUT);
  pinMode(g_rain, OUTPUT);
  pinMode(b_rain, OUTPUT);
  pinMode(led, OUTPUT);
  lcd.setCursor(0, 0);   // Пишем, что идет подготовка системы
  lcd.print("  Preparing of  ");
  lcd.setCursor(0, 1);
  lcd.print("   system...    ");
  for (byte q = 0; q < 11; q++) {   // Мигаем светодиодами для проверки и нагрева системы (2 режима)
    if (prep_type == true) {
      digitalWrite(lamp, 1);
      analogWrite(led, 255);
      digitalWrite(r, 1);
      delay(500);
      digitalWrite(g, 1);
      delay(500);
      digitalWrite(b, 1);
      delay(500);
      digitalWrite(r_rain, 1);
      delay(500);
      digitalWrite(g_rain, 1);
      delay(500);
      digitalWrite(b_rain, 1);
      delay(1000);
      digitalWrite(r, 0);
      digitalWrite(g, 0);
      digitalWrite(b, 0);
      digitalWrite(r_rain, 0);
      digitalWrite(g_rain, 0);
      digitalWrite(b_rain, 0);
      digitalWrite(lamp, 0);
      for (int i = 0; i <= 255; i++) {
        analogWrite(led, i);
        delay(10);
      }
    } else if (prep_type == false) {
      digitalWrite(lamp, 1);
      analogWrite(led, 255);
      digitalWrite(r, 1);
      delay(500);
      digitalWrite(r, 0);
      digitalWrite(g, 1);
      delay(500);
      digitalWrite(g, 0);
      digitalWrite(b, 1);
      delay(500);
      digitalWrite(b, 0);
      digitalWrite(r_rain, 1);
      delay(500);
      digitalWrite(r_rain, 0);
      digitalWrite(g_rain, 1);
      delay(500);
      digitalWrite(g_rain, 0);
      digitalWrite(b_rain, 1);
      delay(500);
      digitalWrite(b_rain, 0);
      digitalWrite(lamp, 0);
      for (int i = 0; i <= 255; i++) {
        analogWrite(led, i);
        delay(10);
      }
    }
  }
  analogWrite(led, 0); // Выключаем аналоговый светодиод
  lcd.setCursor(0, 0); // Пишем, что подготовка завершена
  lcd.print("Preparation was");
  lcd.setCursor(0, 1);
  lcd.print("   completed   ");
  digitalWrite(lamp, 1); // Мигаем лампочкой, извещая о выходе на обычный режим работы
  delay(2000);
  digitalWrite(lamp, 0);
  lcd.setCursor(0, 0); // Стираем все, что писали, освобождая место для вывода показаний
  lcd.print("                ");
  lcd.setCursor(0, 1);
  lcd.print("                ");
  power.hardwareDisable(PWR_UART0 | PWR_UART1 | PWR_UART2 | PWR_UART3 | PWR_SPI);
}
//---------------LOOP---------------
void loop() {
  float temperature = bmp280.readTemperature(); // Опрос датчиков
  float pressure = bmp280.readPressure() / 133.3224;
  gaz = analogRead(mq);
  h = round(dht.readHumidity());
  if (millis() / 1000 <= zhdat_pogoda * 2) {
    analogWrite(led, 255);
  } else {
    analogWrite(led, 0);
  }
  Gaz(); // Определяем газ(функция внизу)
  Pressure(); // Определяем давление(функция внизу)
  // Другие показания:
  if (h > 60 || h < 40 && lamp_indicator == 0) { // Если показатели влажности  не в норме, то
    digitalWrite(lamp, HIGH); // Зажечь сигнал
    lamp_indicator = 1;
  } else if (h >= 40 && h <= 60 && lamp_indicator == 1) { // А если в норме,
    digitalWrite(lamp, LOW); // Убрать сигнал
    lamp_indicator = 0;
  }
  if (pres_sign == true) { //Если хотим показывать давление
    if (pres_zapis > millis()) {
      pres_zapis = 0;
    }
    if (millis() / 1000 - pres_zapis >= t_pres) {
      pres[3] = pres[2];
      pres[2] = pres[1];
      pres[1] = pres[0];
      pres[0] = round(pressure);
      pres_zapis = millis() / 1000;
    }
    lcd.setCursor(0, 0); // Стираем все, что писали, освобождая место для вывода показаний
    lcd.print("                ");
    lcd.setCursor(0, 1);
    lcd.print("                ");
    lcd.setCursor(0, 0); // Выводим показания с давлением
    lcd.print("  4   3   2   1");
    lcd.setCursor(1, 1);
    lcd.print(pres[3]);
    lcd.setCursor(1, 5);
    lcd.print(pres[2]);
    lcd.setCursor(1, 9);
    lcd.print(pres[1]);
    lcd.setCursor(1, 14);
    lcd.print(pres[0]);
    delay(zhdat_pres * 1000); // Ждём время, указанное в настройках
  }
  lcd.setCursor(0, 0); // Стираем все, что писали, освобождая место для вывода показаний
  lcd.print("                ");
  lcd.setCursor(0, 1);
  lcd.print("                ");
  lcd.setCursor(0, 0); // Вывод показаний на дисплей
  lcd.print("Dv: ");
  lcd.print(round(pressure));
  lcd.print(" Vl: ");
  lcd.print(h);
  lcd.print("%");
  lcd.setCursor(0, 1);
  lcd.print("Gz: ");
  lcd.print(gaz);
  lcd.print(" Temp: ");
  lcd.print(round(temperature - 3));
  lcd.print("C");
  delay(zhdat * 1000);
}
//-----------ФУНКЦИИ-----------------
void Gaz() { // Функция определения газов
  if (gaz > 52 && gaz_b != 1) {
    gaz_b = 1; // Первый, т. е. высший уровень опасности
  }
  if (gaz > 45 && gaz < 53 && gaz_b != 2) {
    gaz_b = 2; // Второй уровень опасности
  }
  if (gaz < 46 && gaz > 38 && gaz_b != 3) {
    gaz_b = 3; // Третий уровень опасности
  } else if (gaz < 37 && gaz_b != 4) {
    gaz_b = 4; // Совсем мало угл. газа
  }
  // Вывод показаний газа на лампочку:
  if (gaz_b == 1) { // Если газа много, нужно зажечь красный свет и забыть
    digitalWrite(r, HIGH);
    digitalWrite(g, LOW);
    digitalWrite(b, LOW);
  }
  if (gaz_b == 2) { // Если второй уровень, нужно включить зеленый цвет и забыть
    digitalWrite(g, HIGH);
    digitalWrite(r, LOW);
    digitalWrite(b, LOW);
  }
  if (gaz_b == 3) { // Если третий, включить сине-зелёный и забыть
    digitalWrite(b, HIGH);
    digitalWrite(g, HIGH);
    digitalWrite(r, LOW);
  }
  if (gaz_b == 4) { //Если 4, включить фиолетовый
    digitalWrite(r,  HIGH);
    digitalWrite(b, HIGH);
    digitalWrite(g, LOW);
  }
  delay(10);
}

void Pressure() { //Функция определения давления
  if (pogoda_zapis > millis()) {
    pogoda_zapis = 0;
  }
  if (millis() / 1000 - pogoda_zapis >= zhdat_pogoda) { // Если прошло zhdat_pogoda
    weather[1] = weather[0]; // То свежее показание теперь старое
    weather[0] = round(pressure); // А свежим будет новое
    pogoda_zapis = millis() / 1000;
  }
  if (weather[0] - weather[1] == 0 && dvl_b != 1) { // Если давление не менялось и переменная не знает об этом
    dvl_b = 1; // Сказать ей
  }
  if (weather[0] - weather[1] >= 2 && dvl_b != 2) { // Если давление стало ниже и переменная не знает об этом
    dvl_b = 2; // Сказать ей
  }
  if (weather[0] - weather [1] <= (-2) && dvl_b != 3) { // Если давление стало больше и переменная не знает об этом
    dvl_b = 3; // Сказать ей
  }
  if (dvl_b == 1) {  // При неизменной погоде вкл. зелёный цвет
    digitalWrite(g_rain, HIGH);
    digitalWrite(b_rain, LOW);
    digitalWrite(r_rain, LOW);
  }
  if (dvl_b == 2) { // При ухудшении погоды - вкл. синюю лампочку
    digitalWrite(b_rain, HIGH);
    digitalWrite(g_rain, LOW);
    digitalWrite(r_rain, LOW);
  }
  if (dvl_b == 3) { // При улучшении погоды - вкл. красный цвет
    digitalWrite(r_rain, HIGH);
    digitalWrite(b_rain, LOW);
    digitalWrite(g_rain, LOW);

  }
  delay(10);
}

Код проблемного места:

if (pres_sign == true) { //Если хотим показывать давление (указано в настройках)
    if (pres_zapis > millis()) { //сброс если переполнение переменной
      pres_zapis = 0;
    }
    if (millis() / 1000 - pres_zapis >= t_pres) { //если прошло t_pres (указано в настройках в секундах),
      pres[3] = pres[2]; //перезаписать массив
      pres[2] = pres[1];
      pres[1] = pres[0];
      pres[0] = round(pressure);
      pres_zapis = millis() / 1000;
    }
    lcd.setCursor(0, 0); // Стираем все, что писали, освобождая место для вывода показаний
    lcd.print("                ");
    lcd.setCursor(0, 1);
    lcd.print("                ");
    lcd.setCursor(0, 0); // Выводим показания с давлением
    lcd.print("  4   3   2   1");
    lcd.setCursor(1, 1);
    lcd.print(pres[3]);
    lcd.setCursor(1, 5);
    lcd.print(pres[2]);
    lcd.setCursor(1, 9);
    lcd.print(pres[1]);
    lcd.setCursor(1, 14);
    lcd.print(pres[0]);
    delay(zhdat_pres * 1000); // Ждём время, указанное в настройках
  }

Код функции Pressure():

void Pressure() { //Функция определения давления
  if (pogoda_zapis > millis()) { //защита от переполнения

    pogoda_zapis = 0;

  }

  if (millis() / 1000 - pogoda_zapis >= zhdat_pogoda) { // Если прошло zhdat_pogoda

    weather[1] = weather[0]; // То свежее показание теперь старое

    weather[0] = round(pressure); // А свежим будет новое

    pogoda_zapis = millis() / 1000;

  }

  if (weather[0] - weather[1] == 0 && dvl_b != 1) { // Если давление не менялось и переменная не знает об этом

    dvl_b = 1; // Сказать ей

  }

  if (weather[0] - weather[1] >= 2 && dvl_b != 2) { // Если давление стало ниже и переменная не знает об этом

    dvl_b = 2; // Сказать ей

  }

  if (weather[0] - weather [1] <= (-2) && dvl_b != 3) { // Если давление стало больше и переменная не знает об этом

    dvl_b = 3; // Сказать ей

  }

  if (dvl_b == 1) {  // При неизменной погоде вкл. зелёный цвет

    digitalWrite(g_rain, HIGH);

    digitalWrite(b_rain, LOW);

    digitalWrite(r_rain, LOW);

  }

  if (dvl_b == 2) { // При ухудшении погоды - вкл. синюю лампочку

    digitalWrite(b_rain, HIGH);

    digitalWrite(g_rain, LOW);

    digitalWrite(r_rain, LOW);

  }

  if (dvl_b == 3) { // При улучшении погоды - вкл. красный цвет

    digitalWrite(r_rain, HIGH);

    digitalWrite(b_rain, LOW);

    digitalWrite(g_rain, LOW);

  }

  delay(10);

}

Переменные:

t_pres  - раз во сколько делать замер

pres_zapis – записанное время с последнего замера

zhdat_pres – сколько времени выводить показатели на дисплей

pres[*] – массив давления

 

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

Может стоит к автору кода обратится?

bdbd_dbdb
Offline
Зарегистрирован: 23.12.2020

Так я и автор этого кода

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

loop надо переписать полностью

bdbd_dbdb
Offline
Зарегистрирован: 23.12.2020

Что нужно исправить?

sadman41
Offline
Зарегистрирован: 19.10.2016

Мне просто интересно - почему любители считают, что отладку их кода нужно производить коллективно?

Любишь кататься, люби и саночки возить.  Написал - отлаживай. Это неотъемлемая часть процесса.

bdbd_dbdb
Offline
Зарегистрирован: 23.12.2020

Я уже пробовал. Если у меня не вышло, я вообще не вижу проблему, почему я не могу спросить? Не для этого ли форумы нужны?

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

bdbd_dbdb пишет:

Не для этого ли форумы нужны?

Нет.

bdbd_dbdb
Offline
Зарегистрирован: 23.12.2020

А для чего же, интересно?

 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017
bdbd_dbdb
Offline
Зарегистрирован: 23.12.2020

Так там и написано: "Чтобы получить помощь"

sadman41
Offline
Зарегистрирован: 19.10.2016

Дальше читайте: "...чтобы возникло желание помочь".

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

bdbd_dbdb
Offline
Зарегистрирован: 23.12.2020

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

rkit
Offline
Зарегистрирован: 23.11.2016

Деление на 1000 выкинь - ужасная идея. И "сброс" твой не нужен. От него только вред.

bdbd_dbdb
Offline
Зарегистрирован: 23.12.2020

Спасибо, сейчас попробую

b707
Offline
Зарегистрирован: 26.05.2017

bdbd_dbdb пишет:

Что нужно исправить?

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

Глубоко не вглядывался. уверен. в коде еще тыщи :) ошибок, но это видно с первого взгляда