Ищу человека который напишет код настройки времени для часов

Bogdan74
Offline
Зарегистрирован: 08.06.2021

Есть часы-метеостанция к ним припаяно 3 кнопки нужно настраивать время через них.

За пример была взята метеостанция от Алекса Гивера https://alexgyver.ru/meteoclock/

Моя схема и уже имеющийся код приведены ниже.

Основной код:

/*
  Время и дата устанавливаются атвоматически при загрузке прошивки (такие как на компьютере)
  График всех величин за час и за сутки (усреднённые за каждый час)
  В модуле реального времени стоит батарейка, которая продолжает отсчёт времени после выключения/сброса питания
  Как настроить время на часах. У нас есть возможность автоматически установить время на время загрузки прошивки, поэтому:
	- Ставим настройку RESET_CLOCK на 1
  - Прошиваемся
  - Сразу ставим RESET_CLOCK 0
  - И прошиваемся ещё раз
  - Всё
*/



// ------------------------- НАСТРОЙКИ --------------------
#define RESET_CLOCK 0     // сброс часов на время загрузки прошивки (для модуля с несъёмной батарейкой). Не забудь поставить 0 и прошить ещё раз!
#define SENS_TIME 30000   // время обновления показаний сенсоров на экране, миллисекунд
#define DISP_MODE 1       // в правом верхнем углу отображать: 0 - год, 1 - день недели, 2 - секундо
#define WEEK_LANG 0       // язык дня недели: 0 - английский, 1 - русский (транслит)
#define DEBUG 0           // вывод на дисплей лог инициализации датчиков при запуске. Для дисплея 1602 не работает! Но дублируется через порт!
#define DISPLAY_ADDR 0x27 // адрес платы дисплея: 0x27 или 0x3f. Если дисплей не работает - смени адрес! На самом дисплее адрес не указан

// адрес BME280 жёстко задан в файле библиотеки Adafruit_BME280.h
// стоковый адрес был 0x77, у китайского модуля адрес 0x76.
// Так что если юзаете не библиотеку из архива - не забудьте поменять

// если дисплей не заводится - поменяйте адрес (строка 54)

// библиотеки
#include <Wire.h>
#include <LiquidCrystal_I2C.h>


LiquidCrystal_I2C lcd(DISPLAY_ADDR, 20, 4);

#include "RTClib.h"
RTC_DS3231 rtc;
DateTime now;

#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BME280 bme;


#include <GyverTimer.h>
GTimer_ms sensorsTimer(SENS_TIME);
GTimer_ms drawSensorsTimer(SENS_TIME);
GTimer_ms clockTimer(1000);

int8_t hrs, mins, secs;
// переменные для вывода
float dispTemp;
byte dispHum;
int dispPres;



// символы
// цифры
uint8_t LT[8] = {0b00111,  0b01111,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111};
uint8_t UB[8] = {0b11111,  0b11111,  0b11111,  0b00000,  0b00000,  0b00000,  0b00000,  0b00000};
uint8_t RT[8] = {0b11100,  0b11110,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111};
uint8_t LL[8] = {0b11111,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111,  0b01111,  0b00111};
uint8_t LB[8] = {0b00000,  0b00000,  0b00000,  0b00000,  0b00000,  0b11111,  0b11111,  0b11111};
uint8_t LR[8] = {0b11111,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111,  0b11110,  0b11100};
uint8_t UMB[8] = {0b11111,  0b11111,  0b11111,  0b00000,  0b00000,  0b00000,  0b11111,  0b11111};
uint8_t LMB[8] = {0b11111,  0b00000,  0b00000,  0b00000,  0b00000,  0b11111,  0b11111,  0b11111};

void drawDig(byte dig, byte x, byte y) {
  switch (dig) {
    case 0:
      lcd.setCursor(x, y); // set cursor to column 0, line 0 (first row)
      lcd.write(0);  // call each segment to create
      lcd.write(1);  // top half of the number
      lcd.write(2);
      lcd.setCursor(x, y + 1); // set cursor to colum 0, line 1 (second row)
      lcd.write(3);  // call each segment to create
      lcd.write(4);  // bottom half of the number
      lcd.write(5);
      break;
    case 1:
      lcd.setCursor(x + 1, y);
      lcd.write(2);
      lcd.setCursor(x + 1, y + 1);
      lcd.write(3);
      break;
    case 2:
      lcd.setCursor(x, y);
      lcd.write(6);
      lcd.write(6);
      lcd.write(2);
      lcd.setCursor(x, y + 1);
      lcd.write(3);
      lcd.write(7);
      lcd.write(7);
      break;
    case 3:
      lcd.setCursor(x, y);
      lcd.write(1);
      lcd.write(6);
      lcd.write(5);
      lcd.setCursor(x, y + 1);
      lcd.write(4);
      lcd.write(7);
      lcd.write(5);
      break;
    case 4:
      lcd.setCursor(x, y);
      lcd.write(3);
      lcd.write(4);
      lcd.write(2);
      lcd.setCursor(x + 2, y + 1);
      lcd.write(3);
      break;
    case 5:
      lcd.setCursor(x, y);
      lcd.write(0);
      lcd.write(6);
      lcd.write(6);
      lcd.setCursor(x, y + 1);
      lcd.write(7);
      lcd.write(7);
      lcd.write(5);
      break;
    case 6:
      lcd.setCursor(x, y);
      lcd.write(0);
      lcd.write(6);
      lcd.write(6);
      lcd.setCursor(x, y + 1);
      lcd.write(3);
      lcd.write(7);
      lcd.write(5);
      break;
    case 7:
      lcd.setCursor(x, y);
      lcd.write(1);
      lcd.write(1);
      lcd.write(5);
      lcd.setCursor(x + 1, y + 1);
      lcd.write(0);
      break;
    case 8:
      lcd.setCursor(x, y);
      lcd.write(0);
      lcd.write(6);
      lcd.write(2);
      lcd.setCursor(x, y + 1);
      lcd.write(3);
      lcd.write(7);
      lcd.write(5);
      break;
    case 9:
      lcd.setCursor(x, y);
      lcd.write(0);
      lcd.write(1);
      lcd.write(2);
      lcd.setCursor(x + 1, y + 1);
      lcd.write(7);
      lcd.write(5);
      break;
    case 10:
      lcd.setCursor(x, y);
      lcd.write(32);
      lcd.write(32);
      lcd.write(32);
      lcd.setCursor(x, y + 1);
      lcd.write(32);
      lcd.write(32);
      lcd.write(32);
      break;
  }
}

void drawdots(byte x, byte y, boolean state) {
  byte code;
  if (state) code = 165;
  else code = 32;
  lcd.setCursor(x, y);
  lcd.write(code);
  lcd.setCursor(x, y + 1);
  lcd.write(code);
}

void drawClock(byte hours, byte minutes, byte x, byte y, boolean dotState) {
  // чисти чисти!
  lcd.setCursor(x, y);
  lcd.print("               ");
  lcd.setCursor(x, y + 1);
  lcd.print("               ");

  //if (hours > 23 || minutes > 59) return;
  if (hours / 10 == 0) drawDig(10, x, y);
  else drawDig(hours / 10, x, y);
  drawDig(hours % 10, x + 4, y);
  // тут должны быть точки. Отдельной функцией
  drawDig(minutes / 10, x + 8, y);
  drawDig(minutes % 10, x + 12, y);
}

#if (WEEK_LANG == 0)
static const char *dayNames[]  = {
  "Sund",
  "Mond",
  "Tues",
  "Wedn",
  "Thur",
  "Frid",
  "Satu",
};
#else
static const char *dayNames[]  = {
  "BOCK",
  "POND",
  "BTOP",
  "CPED",
  "4ETB",
  "5YAT",
  "CYBB",
};
#endif

void drawData() {
  lcd.setCursor(15, 0);
  if (now.day() < 10) lcd.print(0);
  lcd.print(now.day());
  lcd.print(".");
  if (now.month() < 10) lcd.print(0);
  lcd.print(now.month());

  if (DISP_MODE == 0) {
    lcd.setCursor(16, 1);
    lcd.print(now.year());
  } else if (DISP_MODE == 1) {
    lcd.setCursor(16, 1);
    int dayofweek = now.dayOfTheWeek();
    lcd.print(dayNames[dayofweek]);
  }
}



void loadClock() {
  lcd.createChar(0, LT);
  lcd.createChar(1, UB);
  lcd.createChar(2, RT);
  lcd.createChar(3, LL);
  lcd.createChar(4, LB);
  lcd.createChar(5, LR);
  lcd.createChar(6, UMB);
  lcd.createChar(7, LMB);
}





void setup() {
  Serial.begin(9600);
  



  lcd.init();
  lcd.backlight();
  lcd.clear();

#if (DEBUG == 1)
  boolean status = true;

  lcd.setCursor(0, 1);
  lcd.print(F("RTC... "));
  Serial.print(F("RTC... "));
  delay(50);
  if (rtc.begin()) {
    lcd.print(F("OK"));
    Serial.println(F("OK"));
  } else {
    lcd.print(F("ERROR"));
    Serial.println(F("ERROR"));
    status = false;
  }

  lcd.setCursor(0, 2);
  lcd.print(F("BME280... "));
  Serial.print(F("BME280... "));
  delay(50);
  if (bme.begin(&Wire)) {
    lcd.print(F("OK"));
    Serial.println(F("OK"));
  } else {
    lcd.print(F("ERROR"));
    Serial.println(F("ERROR"));
    status = false;
  }

  lcd.setCursor(0, 3);
  if (status) {
    lcd.print(F("All good"));
    Serial.println(F("All good"));
    delay(1000);
    lcd.clear();
  } else {
    lcd.print(F("Check wires!"));
    Serial.println(F("Check wires!"));
    delay(1000);
    while (1);
  }
#else


  rtc.begin();
  bme.begin(&Wire);
#endif

  bme.setSampling(Adafruit_BME280::MODE_FORCED,
                  Adafruit_BME280::SAMPLING_X1, // temperature
                  Adafruit_BME280::SAMPLING_X1, // pressure
                  Adafruit_BME280::SAMPLING_X1, // humidity
                  Adafruit_BME280::FILTER_OFF   );

  if (RESET_CLOCK || rtc.lostPower())
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));

  now = rtc.now();
  secs = now.second();
  mins = now.minute();
  hrs = now.hour();

  bme.takeForcedMeasurement();
  uint32_t Pressure = bme.readPressure();
  


    loadClock();
    drawClock(hrs, mins, 0, 0, 1);
    drawData();
  
  readSensors();
  drawSensors();
}

void loop() {
  if (sensorsTimer.isReady()) readSensors();    // читаем показания датчиков с периодом SENS_TIME


  if (clockTimer.isReady()) clockTick();        // два раза в секунду пересчитываем время и мигаем точками

    if (drawSensorsTimer.isReady()) drawSensors();  // обновляем показания датчиков на дисплее с периодом SENS_TIME
 

}

Код с функциями:


void readSensors() {
  bme.takeForcedMeasurement();
  dispTemp = bme.readTemperature();
  dispHum = bme.readHumidity();
  dispPres = (float)bme.readPressure() * 0.00750062;
}

void drawSensors() {

  lcd.setCursor(0, 2);
  lcd.print(String(dispTemp, 1));
  lcd.write(223);
  lcd.setCursor(6, 2);
  lcd.print(" " + String(dispHum) + "%  ");

  lcd.setCursor(13, 2);
  lcd.print(String(dispPres) + " mm");
  lcd.setCursor(13, 3);

}



boolean dotFlag;
void clockTick() {
  dotFlag = !dotFlag;
  if (dotFlag) {          // каждую секунду пересчёт времени
    secs++;
    if (secs > 59) {      // каждую минуту
      secs = 0;
      mins++;
      if (mins <= 59) drawClock(hrs, mins, 0, 0, 1);
    }
    if (mins > 59) {      // каждый час
      now = rtc.now();
      secs = now.second();
      mins = now.minute();
      hrs = now.hour();
      drawClock(hrs, mins, 0, 0, 1);
      if (hrs > 23) {
        hrs = 0;
      }
      drawData();
    }
   if (DISP_MODE == 2) {
      lcd.setCursor(16, 1);
      if (secs < 10) lcd.print(" ");
      lcd.print(secs);
    } 
  }
  drawdots(7, 0, dotFlag);
  
}

 

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

Если есть wifi, замените ардуину на esp8266 и получайте наиточнейшее время с NTP. Не думаю, что заказ станет от этого сильно дороже, но станет сильно удобнее

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

...все равно кнопки неправильно пририсованы.

Но тогда придётся как-то вводить SSID, passphrase и адрес NTP.

Даже не знаю, что лучше.

Bogdan74
Offline
Зарегистрирован: 08.06.2021

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

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

sadman41 пишет:
Но тогда придётся как-то вводить SSID, passphrase и адрес NTP. Даже не знаю, что лучше.

NTP не надо вводить, их достаточно штук 20 проверенных прописать в цикл перебора. Могу скинуть свои топ-20. Вэб-морду писать придется, это да! Еще и кэш логин-пароль.. Но, что-то мне подсказывает, что для вас это не сильно обременительно)) И это решение будет всяко удобнее кнопок

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

Bogdan74 пишет:

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

А так они еще и с телефона будут управляться! Годнота, да и только!

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

Для меня - нет, для заказчика - скорее всего.

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

sadman41 пишет:
Для меня - нет, для заказчика - скорее всего.

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

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

Rumata пишет:

sadman41 пишет:
Для меня - нет, для заказчика - скорее всего.

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


Это и есть его бремя ))

Bogdan74
Offline
Зарегистрирован: 08.06.2021

У меня просто требование сделать с кнопками.
В принципе, я би уже давно всё сделал бы, но есть проблема, я уже нашел неплохой код настройки на https://lesson.iarduino.ru/page/urok-17-podklyuchenie-rtc-chasy-realnogo...
Но проблема в том что там другая библиотека, и при простом переносе - функции не работают, а при замене библиотеки - не работает пол кода.

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

sadman41 пишет:

Это и есть его бремя ))

Это не бремя, Это рыночные отношения. Вот вам ведь тоже знания и опыт даром не достались? И он, возможно, в чем-то профессионал. Теория вмененных издержек советует заниматься за деньги профильным делом, а непрофильные задачи отдавать на аутсорсинг. 

 

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

Bogdan74 пишет:
У меня просто требование сделать с кнопками.

Ну, это ваши личные проблемы. Решайте их с исполнителем

Bogdan74
Offline
Зарегистрирован: 08.06.2021

Возможно я начал тему не в том разделе, просто меня немного напрягло то, что я брал за основу чужой проект, а на форуме написано что "Здесь помогают тем, кто пытается что-то сделать сам, имеет самописный скетч и задает вопросы по нему. Если вас не устраивают требования, есть чудесный раздел: "Ищу исполнителя"."

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

Bogdan74 пишет:
Возможно я начал тему не в том разделе, просто меня немного напрягло то, что я брал за основу чужой проект, а на форуме написано что "Здесь помогают тем, кто пытается что-то сделать сам, имеет самописный скетч и задает вопросы по нему. Если вас не устраивают требования, есть чудесный раздел: "Ищу исполнителя"."

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

UPD: 74 это регион, или другое?))

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

Bogdan74, огласите бюджет, пожалуйста

Бармалей
Бармалей аватар
Offline
Зарегистрирован: 23.09.2019

Бюджет неважен. Напишите мне на почту barmaley2m@yandex.ru