Большие часы на адресных светодиодах WS2812B

Большие часы на адресных светодиодах WS2812B
Всем привет, хочу рассказать о том как я попробовал повторить проект, но столкнулся с некоторыми проблемами.

Как-то раз на просторах зарубежного интернета я нашел вот такой проект часов на базе светодиодной ленты WS2812B: Big, Auto Dim, Room Clock, и мне захотелось его повторить. Часы устроены как семи сегментный циферблат и работают на RTC модуле DS3231 . Часы умеют показывать температуру, имеют кнопки для настройки и перевода на зимнее время и обратно, позже я добавил датчик влажности DHT11. Температура уже вместе с влажностью считывалась с этого датчика и выводилась раз в минуту. Хоть и в модуле часов есть температурный датчик, но похоже он показывал температуру не корректно из-за самонагрева (ИМХО).




Untitled Sketch_МП.png
И главное нанести много горячих соплей

IMG_20180907_120755.jpg


Когда все было собрано, повозившись с библиотеками, все заработало. И тут возникло одно большое НО: положения яркости в только в двух позициях меня не устраивало. Тем более на границе значений происходило мерцание. Установка яркости на статичном значении меня тоже не очень устраивала ибо днем при установленном тусклом свете ничего не было видно, а ночью даже со значениями близким к минимуму можно было осветить всю Москву. Поинтересовавшись как в других проектах с этим справляется Alex было решено заменить такой код настройки яркости.

C:
void BrightnessCheck(){
  const byte sensorPin = BRI_PIN; // light sensor pin
  const byte brightnessLow = 1; // Low brightness value
  const byte brightnessHigh = 50; // High brightness value
  int sensorValue = analogRead(sensorPin); // Read sensor
  Serial.print("Sensor is: ");Serial.println(sensorValue);
  sensorValue = map(sensorValue, 0, 255, 1, 100);
  LEDS.setBrightness(sensorValue);
  };
вот такими строчками:
C:
void BrightnessCheck() {

  if (auto_bright) {                         // если включена адаптивная яркость
    if (millis() - bright_timer > 100) {     // каждые 100 мс
      bright_timer = millis();               // сброить таймер
      new_bright = map(analogRead(BRI_PIN), 0, bright_constant, min_bright, max_bright);   // считать показания с фоторезистора, перевести диапазон
      new_bright = constrain(new_bright, min_bright, max_bright);
      new_bright_f = new_bright_f * coef + new_bright * (1 - coef);
      LEDS.setBrightness(new_bright_f);      // установить новую яркость
    }
  }
};

Тут стоит упомянуть что программистом я не являюсь и большинство проблем я пытаюсь решить методом тыка и перебора.

И тут все заработало, моей радости не было придела, пока не наступила ночь. Появилась проблема с отключением ленты при полной темноте. Иногда это было только на минуту, а иногда на целую ночь. Еще есть проблема со слабим мерцанием светодиодов если освещения в комнате было мало (например когда работал телик), но это было редко и длилось это одну минуту.

Что касается кода вот сылка на GitHub. Кое-что я перевел для лучшего понимания.

Давно хотел поделиться готовым и работоспособным проектом в кругах аудитории Алекса, но вышло так что собственно нормальной работоспособностью тут не пахнет. Буду благодарени, если у кто сможет помочь.
 
Изменено:

Комментарии

kym13

★★✩✩✩✩✩
14 Ноя 2020
529
74
вот скетч. и если не трудно закомментируй строку со временем или подскажите где это сделать . я не силен в ардуино.
А Вы время уже на модуле установили?

В этом скетче время берётся с модуля DS3231 и выставляется кнопками которые подключены к: читай в начале скетча
//Кнопки: Смена часов -> D2 замыкаешь на GND меняешь цифру часов
// Смена минут -> D3 замыкаешь на GND меняешь цифру минут
// Смена цвета -> D4 замыкаешь на GND меняешь цвет цифр
у меня вместо кнопок кусочки провода т.е. подключаешь проводок если кнопок нет на пример к D2 и замыкаешь на GND будут меняться цифры часов, аналогично с минутами.
В начале скетча я вам написал

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

вернее не так. после отключения питания часы показывают то время которое установил при заливке скетча. может причина в ардуинке
Ну всё правильно так и должно быть, если отстают немного в скетче есть кнопки подстройки часов и минут, правда секунды не обнуляются

alli
Прошейте сначала скетчем из 548 поста, на модуль DS3231 установиться время которое у вас на компьютере(надеюсь оно у Вас точно установлено), затем прошейте свой скетч и будет Вам счастье.
 

Вложения

ASM

★★★★★✩✩
26 Окт 2018
1,693
339
Блин, что такой модуль bme280 дорогой стал на Али) 400-500р и доставка 200-250р, надо что-то попроще тогда найти для влажности)
 

kym13

★★✩✩✩✩✩
14 Ноя 2020
529
74
Блин, что такой модуль bme280 дорогой стал на Али) 400-500р и доставка 200-250р, надо что-то попроще тогда найти для влажности)
Мне повезло, нарвался как-то за 1,8$ с бесплатной доставкой пару заказал 5 вольтовых сразу. А сейчас залез на страницу продавца 350р + 320р доставка, китайцы офигели. Вообще искать надо, я сейчас полазил по Али нашел за 48р с бесплатной доставкой правда 3,3v питание.
Забей в поиск на Али, я нашел дешевые только на 3,3v за 46р. Не пойму логику китайцев, модуль с подключением по I2C и 5v питанием стоит дороже чем модуль с подключением по I2C/SPI с 3,3v питанием, неужели стабилизатор на 3,3v стоит так дорого
 
Изменено:

ASM

★★★★★✩✩
26 Окт 2018
1,693
339
Так нам и надо на 3,3В. На ESP нет 5В, только если брать с БП. Дешёвые, это BMP.
Надо тогда смотреть датчики влажности отдельно, типа DHT. Они намного дешевле, только видов много, надо выбрать какой-то) Чтобы бюджетно было, высокой точности не требуется)
 

kym13

★★✩✩✩✩✩
14 Ноя 2020
529
74
Да в принципе влажность то не очень и нужна, а вот барометр это тема. Я уже научился погоду предсказывать по барометру на 99% совпадает.
 

ASM

★★★★★✩✩
26 Окт 2018
1,693
339
@kym13, я хочу добавить влажность, есть со стрелками, но сверить показания не с чем)
Надо тогда 1302 перекидывать на Ардуино и проводить эксперименты с 3231. Ждал мыслей от программистов, но что-то не отвечают)
 

kym13

★★✩✩✩✩✩
14 Ноя 2020
529
74
ASM
Надо тогда 1302 перекидывать на Ардуино....... Не подскажешь как в скетч вместо 3231 добавить другие часы
 

ASM

★★★★★✩✩
26 Окт 2018
1,693
339
@kym13, так смотри примеры в библиотеке, там всё указано, 1307 точно есть, поменять минимально) а вот на 1302 надо другую либу, походу, надо посмотреть первые версии скетча, когда делал на 1302)

какая библиотека у тебя в скетче под часы?
нашел универсальную)
 
Изменено:

kym13

★★✩✩✩✩✩
14 Ноя 2020
529
74
@kym13, так смотри примеры в библиотеке, там всё указано, 1307 точно есть, поменять минимально) а вот на 1302 надо другую либу, походу, надо посмотреть первые версии скетча, когда делал на 1302)

какая библиотека у тебя в скетче под часы?
нашел универсальную)
Вставил в скетч который <Clock_WiFi_01 и Clock_WiFi_03> DS1307 они компилируются но не выводят на табло, библиотеку не менял стоит эта <RTClib.h>

Библиотеки по ссылке у меня есть, <Clock_WiFi_03 > это я обозвал Clock_WiFi_01 после дополнений чтобы не путаться
 

kym13

★★✩✩✩✩✩
14 Ноя 2020
529
74

ASM

★★★★★✩✩
26 Окт 2018
1,693
339
@kym13, экспериментировал с кодом.
Заметил одну особенность. Загружаешь, если время не определилось, меняешь в строке случайное число и время обновляется принудительно...
сейчас адаптирую без еепрома, чтобы обновлялось раз в 5 минут, для теста)
C++:
#include <ESP8266WiFi.h>
#include <EasyNTPClient.h>
#include <WiFiUdp.h>
#include <RTClib.h>
RTC_DS3231 rtc;
#include <EEPROM.h>

const char *ssid = "";
const char *password = "";

WiFiUDP udp;
EasyNTPClient ntpClient(udp, "pool.ntp.org", (3 * 60 * 60));
int timeUpdated = 0;
// Принудительное обновление RTC и сохранение в EEPROM
// измените это на случайное число от 0 до 255, чтобы принудительно обновить время
#define FORCE_RTC_UPDATE 5

void setup() {
  Serial.begin(115200);
  EEPROM.begin(4);

  if (!rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }

  Serial.println("Waiting to Start....");
  delay(5000);

  // Считываем EEPROM, чтобы проверить, синхронизировано ли время
  byte addvalue = EEPROM.read(timeUpdated);
  Serial.print("EEPROM: ");
  Serial.print(addvalue);
  Serial.print(" == ");
  Serial.print(FORCE_RTC_UPDATE);
  Serial.println(" ?");
  if (addvalue != FORCE_RTC_UPDATE) {
    Serial.println("Принудительное обновление");
    syncTime();
    Serial.println("Обновление EEPROM..");
    EEPROM.write(timeUpdated, FORCE_RTC_UPDATE);
    EEPROM.commit();

  } else {
    Serial.println("Время было обновлено раньше...EEPROM проверен");
    Serial.print("EEPROM: ");
    Serial.print(addvalue);
    Serial.print(" = ");
    Serial.print(FORCE_RTC_UPDATE);
    Serial.println("!");
  }
}
void syncTime() {
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  long ntpTime = ntpClient.getUnixTime();
  Serial.print("NTP "); Serial.println(ntpTime);
  rtc.adjust(DateTime(ntpTime));

  // Выключаем WIFI после обновления
  //  WiFi.disconnect();
  //  WiFi.mode(WIFI_OFF);
  //  WiFi.forceSleepBegin();
}
int GetTime() {
  //    long ntpTime = ntpClient.getUnixTime();
  DateTime now = rtc.now();
  //  int unix = now.unixtime();

  Serial.print(now.hour());   Serial.print(":");  // вывод часов
  Serial.print(now.minute()); Serial.print(":");  // вывод минут
  Serial.print(now.second()); Serial.println(""); // вывод секунд
  //  Serial.print("UNIX ");Serial.println(unix);
  Serial.println("");
};
void loop() {
  GetTime();
  delay(1000);
}
 
Изменено:

kym13

★★✩✩✩✩✩
14 Ноя 2020
529
74
Избыточное цитирование
@kym13, экспериментировал с кодом.
Заметил одну особенность. Загружаешь, если время не определилось, меняешь в строке случайное число и время обновляется принудительно...
сейчас адаптирую без еепрома, чтобы обновлялось раз в 5 минут, для теста)
C++:
#include <ESP8266WiFi.h>
#include <EasyNTPClient.h>
#include <WiFiUdp.h>
#include <RTClib.h>
RTC_DS3231 rtc;
#include <EEPROM.h>

const char *ssid = "";
const char *password = "";

WiFiUDP udp;
EasyNTPClient ntpClient(udp, "pool.ntp.org", (3 * 60 * 60));
int timeUpdated = 0;
// Принудительное обновление RTC и сохранение в EEPROM
// измените это на случайное число от 0 до 255, чтобы принудительно обновить время
#define FORCE_RTC_UPDATE 5

void setup() {
  Serial.begin(115200);
  EEPROM.begin(4);

  if (!rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }

  Serial.println("Waiting to Start....");
  delay(5000);

  // Считываем EEPROM, чтобы проверить, синхронизировано ли время
  byte addvalue = EEPROM.read(timeUpdated);
  Serial.print("EEPROM: ");
  Serial.print(addvalue);
  Serial.print(" == ");
  Serial.print(FORCE_RTC_UPDATE);
  Serial.println(" ?");
  if (addvalue != FORCE_RTC_UPDATE) {
    Serial.println("Принудительное обновление");
    syncTime();
    Serial.println("Обновление EEPROM..");
    EEPROM.write(timeUpdated, FORCE_RTC_UPDATE);
    EEPROM.commit();

  } else {
    Serial.println("Время было обновлено раньше...EEPROM проверен");
    Serial.print("EEPROM: ");
    Serial.print(addvalue);
    Serial.print(" = ");
    Serial.print(FORCE_RTC_UPDATE);
    Serial.println("!");
  }
}
void syncTime() {
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  long ntpTime = ntpClient.getUnixTime();
  Serial.print("NTP "); Serial.println(ntpTime);
  rtc.adjust(DateTime(ntpTime));

  // Выключаем WIFI после обновления
  //  WiFi.disconnect();
  //  WiFi.mode(WIFI_OFF);
  //  WiFi.forceSleepBegin();
}
int GetTime() {
  //    long ntpTime = ntpClient.getUnixTime();
  DateTime now = rtc.now();
  //  int unix = now.unixtime();

  Serial.print(now.hour());   Serial.print(":");  // вывод часов
  Serial.print(now.minute()); Serial.print(":");  // вывод минут
  Serial.print(now.second()); Serial.println(""); // вывод секунд
  //  Serial.print("UNIX ");Serial.println(unix);
  Serial.println("");
};
void loop() {
  GetTime();
  delay(1000);
}

22:13:15.488 -> EEPROM: 5 == 5 ?
22:13:15.488 -> Время было обновлено раньше...EEPROM проверен
22:13:15.488 -> EEPROM: 5 = 5!
22:13:15.488 -> 165:165:85
22:13:15.488 ->
22:13:16.471 -> 165:165:85
22:13:16.471 ->
22:13:17.491 -> 165:165:85
22:13:17.491 ->
22:13:18.477 -> 165:165:85
22:13:18.477 ->
22:13:19.496 -> 165:165:85
22:13:19.496 ->
22:13:20.481 -> 165:165:85
22:13:20.481 ->
22:13:21.500 -> 165:165:85
это у меня кажет
 

ASM

★★★★★✩✩
26 Окт 2018
1,693
339
Все, заработало)
Осталось протестировать вывод в loop, правильно ли сделал код в millis для обновления раз в 5 минут...
C++:
#include <ESP8266WiFi.h>
#include <EasyNTPClient.h>
#include <WiFiUdp.h>
#include <RTClib.h>
RTC_DS3231 rtc;

const char *ssid = "";
const char *password = "";

WiFiUDP udp;
EasyNTPClient ntpClient(udp, "pool.ntp.org", (3 * 60 * 60));

void setup() {
  Serial.begin(115200);
  if (!rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }
  Serial.println("Обновление");
  syncTime();
}

void syncTime() {
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  long ntpTime = ntpClient.getUnixTime();
  rtc.adjust(DateTime(ntpTime));
  Serial.println("Обновление...");

  // Выключаем WIFI после обновления
  WiFi.disconnect();
  WiFi.mode(WIFI_OFF);
  WiFi.forceSleepBegin();
}
int GetTime() {
  DateTime now = rtc.now();
  Serial.print(now.hour());   Serial.print(":");  // вывод часов
  Serial.print(now.minute()); Serial.print(":");  // вывод минут
  Serial.print(now.second()); Serial.println(""); // вывод секунд
  delay(1000);
};
void loop() {
  uint32_t newtime = millis() % 300000 / 1000;
  if (newtime <= 300) {
    GetTime();
  }
  else {
    syncTime();
    newtime = 0;
  }
}
это у меня кажет
правильно подключай часики)
Подключаем вывод SDA к выводу D2, SCL к выводу D1, питание можно к 3,3В
 

kym13

★★✩✩✩✩✩
14 Ноя 2020
529
74
Избыточное цитирование
Все, заработало)
Осталось протестировать вывод в loop, правильно ли сделал код в millis для обновления раз в 5 минут...
C++:
#include <ESP8266WiFi.h>
#include <EasyNTPClient.h>
#include <WiFiUdp.h>
#include <RTClib.h>
RTC_DS3231 rtc;

const char *ssid = "";
const char *password = "";

WiFiUDP udp;
EasyNTPClient ntpClient(udp, "pool.ntp.org", (3 * 60 * 60));

void setup() {
  Serial.begin(115200);
  if (!rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }
  Serial.println("Обновление");
  syncTime();
}

void syncTime() {
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  long ntpTime = ntpClient.getUnixTime();
  rtc.adjust(DateTime(ntpTime));
  Serial.println("Обновление...");

  // Выключаем WIFI после обновления
  WiFi.disconnect();
  WiFi.mode(WIFI_OFF);
  WiFi.forceSleepBegin();
}
int GetTime() {
  DateTime now = rtc.now();
  Serial.print(now.hour());   Serial.print(":");  // вывод часов
  Serial.print(now.minute()); Serial.print(":");  // вывод минут
  Serial.print(now.second()); Serial.println(""); // вывод секунд
  delay(1000);
};
void loop() {
  uint32_t newtime = millis() % 300000 / 1000;
  if (newtime <= 300) {
    GetTime();
  }
  else {
    syncTime();
    newtime = 0;
  }
}

правильно подключай часики)
Подключаем вывод SDA к выводу D2, SCL к выводу D1, питание можно к 3,3В
Так модуль часов подключен, а это для какого модуля?

Теперь так кажет, я подключил 1307
22:29:01.282 -> Обновление...
22:29:01.418 -> 165:165:85
22:29:02.437 -> 165:165:85
22:29:03.422 -> 165:165:85
22:29:04.441 -> 165:165:85
22:29:05.426 -> 165:165:85
22:29:06.443 -> 165:165:85
22:29:07.428 -> 165:165:85
22:29:08.446 -> 165:165:85
22:29:09.431 -> 165:165:85
22:29:10.417 -> 165:165:85
22:29:11.435 -> 165:165:85
22:29:12.419 -> 165:165:85
22:29:13.630 -> 165:165:85
22:29:14.428 -> 165:165:85
 

ASM

★★★★★✩✩
26 Окт 2018
1,693
339
@kym13, 1307 тоже судя по инету должен быть на этих пинах, у тебя так?)
 

kym13

★★✩✩✩✩✩
14 Ноя 2020
529
74
@kym13, 1307 тоже судя по инету должен быть на этих пинах, у тебя так?)
Да это же стандарт I2C SDA ->D2, CKL->D1
Стало быть у меня время берёт с 1307? или из нета? в скетче вроде нет строки с сервером времени
22:47:30.091 -> 165:165:85
22:47:40.109 -> 165:165:85
22:47:50.102 -> 165:165:85
22:48:00.090 -> 165:165:85
 

Вложения

kym13

★★✩✩✩✩✩
14 Ноя 2020
529
74
@Старик Похабыч, @bort707, ребят, подскажите, как правильно сделать в loop
C++:
 uint32_t newtime = millis() % 300000 / 1000;
  if (newtime <= 300) {
    GetTime();
  }
  else {
    syncTime();
    newtime = 0;
  }
каждые 5 минут обновлять время
по коду пока время меньше 300 секунд показывать время, если больше, то обновить и обнулить переменную
А зачем так часто время обновлять?
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,272
1,303
Москва
Так работать не будет.
1) 300 никогда не будет. будет 299 и потом 0
2) в приведенном ниже варианте когда будет 299 пойдет на else
А дальше будет все зависеть от того, сколько длиться это самое syncTime(); если в районе секунды или больше, то сработает один раз и пойдет дальше работать нормально. А если меньше, то пока будет идти эта самая 299 секунда будет попадать на syncTime();
Самый тупой вариант для теста сделать задержку 1000мс. А реально надо внутри syncTime(); сделать проверку, что бы выполнялась не реже 1 раза в секунду (тут в секунду) или минут или другой диапазон.
3) newtime = 0; - просто лишнее, новое значение вычисляется непосредственно перед условием.

C++:
 uint32_t newtime = millis() % 300000 / 1000;
  if (newtime <299) {
    GetTime();
  }
  else {
    syncTime();
  }
 
  • Лойс +1
Реакции: ASM