Большие часы на адресных светодиодах 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. Кое-что я перевел для лучшего понимания.

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

Комментарии

Serzh2000

✩✩✩✩✩✩✩
8 Фев 2021
15
7
надо подумать. остановить часы не получится, а вот, например при нажатии двух кнопок вывести секунды на экран и нажатием + или - обнулять секунды... наверно так.
а вы пробовали залить скетч от Владислава по-моему распайка сегментов одинаковая. кнопок только три это можно исправить.
 
  • Лойс +1
Реакции: kym13

влад 55

✩✩✩✩✩✩✩
2 Июн 2020
6
0
Оформи код соответствующим тэгом, см. Правила
В моем скетче код такой-
uint8_t digits[] = { // определяем символы для отображения
// код начинается с 0b0, далее идут 7 цифр, каждая цифра это номер фрагмента, 1 - включен, 0- отключен
// далее указан получающийся символ и порядковый номер в массиве
0b00111111, // Digit 0
0b00100001, // Digit 1
0b01110110, // Digit 2
0b01110011, // Digit 3
0b01101001, // Digit 4
0b01011011, // Digit 5
0b01011111, // Digit 6
0b00110001, // Digit 7
0b01111111, // Digit 8
0b01111011, // Digit 9
0b01111000, // Digit * градус 10
0b00000000, // Digit пусто 11 ничего не показывать
0b01111100, // Digit P 12
0b01111000, // Digit % знак % из двух частей 13
0b01000111, // Digit % знак % из двух частей 14
// 0b01011000, // Digit с маленькая "С" справа вверху 15 если нужна большая закоментируйте эту строку и наоборот
0b00011110, // Digit с большая "С" справа 15 если нужна большая раскоментируйте эту строку и наоборот
// 0b01000000, // знак (-) минус 16

А у Владислава такой
//===================== Формирование цифр и знаков, какой символ из чего состоит =============================

byte digits[24] = {
0b01111110, // 0 // все начинаются с 0b0 далее 7 сегментов цифры (0 - откл, 1-вкл) справа на лево
0b01000010, // 1
0b00110111, // 2
0b01100111, // 3
0b01001011, // 4
0b01101101, // 5
0b01111101, // 6
0b01000110, // 7
0b01111111, // 8
0b01101111, // 9
0b00001111, // º 10
// 0b00001101, // с 11 "с" маленькая, раскоментировать если нужно, большую "С" закоментировать
0b00111100, // C 11 "С" большая, закоментировать если включаете маленькую "с"
0b01011011, // H 12
0b01011111, // A 13
0b01101101, // S 14
0b00000001, // - 15
0b01110011, // d 16
0b01111001, // b 17
0b00000000, // 18 пустой отключен
0b00111001, // t 19
0b00111000, // L 20
0b00011111, // P 21
0b00001111, // % 22
0b01110001 // % 23
не так как в моем , да и не хочется делать новую плату
 

kym13

★★✩✩✩✩✩
14 Ноя 2020
617
90
@влад 55,И в чем разница? Судя по картинке подключения диодов которую вы выкладывали ранее одно и тоже. Дело не в том как формируются цифры, а в последовательности соединения диодов. Если диоды соединенны как на фото то и плату переделывать не надо просто прошить другой скетч.
 

влад 55

✩✩✩✩✩✩✩
2 Июн 2020
6
0
Ладно, не забивайте себе голову, пусть остается прошивка какая есть.Спасибо за участие.
 

seriy76

✩✩✩✩✩✩✩
18 Окт 2023
5
2
Помогите с прошивкой с 69 стр. Несилен в программировании. Нужна с рабочим пунктом изменения яркости. 0-авто и 1-25 -ручная.
 

Serzh2000

✩✩✩✩✩✩✩
8 Фев 2021
15
7
влад 55, попробуй .
при каждом нажатии на кнопку buttonM (увеличении минуты) секунды обнуляются.
например: сейчас на эталонных часах 17:33:06
подводим часы до 17... и минуты 33 и ждем когда на эталонных часах часах будет 17:34:00 и жмем кнопку buttonM (увеличении минуты) ... прибавится минута (будет 34) и обнулятся секунды.
надеюсь понятно объяснил. сам прошивку (скетч) не проверял, потом отпишись нормально или нет.
 

Вложения

  • Лойс +1
Реакции: влад 55

nick 56

★✩✩✩✩✩✩
11 Апр 2024
105
35
А что Вы используете в качестве эталона? У меня в доме трое часов, подключенных к интернету, на одном роутере, айпишники разные и то с разницей секунд в пять говорят время. А телек так ещё больше отстаёт. Так, что синхронизировать по секундам смысла нет.
 
  • Лойс +1
Реакции: kym13

serbakovigor795

✩✩✩✩✩✩✩
20 Апр 2023
1
0
#include "FastLED.h" // Библиотека для управления адресной лентой
#include "DHT.h" // Библиотека для работы с датчиком температуры и влажности

// Настройки ленты
#define NUM_LEDS 30 // Общее количество светодиодов (4 разряда по 7 сегментов + 2 точки)
#define DATA_PIN 6 // Пин подключения ленты
#define COLOR_ORDER GRB // Порядок цветов для ленты
CRGB leds[NUM_LEDS]; // Массив для управления светодиодами

// Пины для кнопок настройки времени
#define HUR_PIN 3 // Пин кнопки настройки часов
#define MIN_PIN 4 // Пин кнопки настройки минут
#define PHOTO_PIN A0 // Пин фоторезистора

// Настройки датчика температуры и влажности
#define DHT_PIN 5 // Пин подключения датчика DHT11/DHT22
#define DHT_TYPE DHT11 // Тип датчика (DHT11 или DHT22)
DHT dht(DHT_PIN, DHT_TYPE); // Инициализация датчика

// Переменные для хранения времени
int hours = 12; // Начальное время: 12:00
int minutes = 0;
unsigned long previousMillis = 0; // Для отслеживания времени
const long interval = 60000; // Интервал обновления времени (1 минута)

// Настройки яркости
int minBrightness = 10; // Минимальная яркость
int maxBrightness = 255; // Максимальная яркость
int currentBrightness = 100; // Текущая яркость
bool isNightMode = false; // Режим энергосбережения (ночной режим)

// Массив для отображения цифр на 7-сегментном индикаторе
byte digits[10][7] = {
{1, 1, 1, 1, 1, 1, 0}, // 0
{0, 1, 1, 0, 0, 0, 0}, // 1
{1, 1, 0, 1, 1, 0, 1}, // 2
{1, 1, 1, 1, 0, 0, 1}, // 3
{0, 1, 1, 0, 0, 1, 1}, // 4
{1, 0, 1, 1, 0, 1, 1}, // 5
{1, 0, 1, 1, 1, 1, 1}, // 6
{1, 1, 1, 0, 0, 0, 0}, // 7
{1, 1, 1, 1, 1, 1, 1}, // 8
{1, 1, 1, 1, 0, 1, 1} // 9
};

// Цвета для сегментов
CRGB segmentColors[5] = {CRGB::Blue, CRGB::Green, CRGB::Red, CRGB::purple, CRGB::Yellow};
int currentColorIndex = 0; // Индекс текущего цвета

// Анимация смены времени
bool isAnimating = false;
unsigned long animationStartTime = 0;
const long animationDuration = 1000; // Длительность анимации (1 секунда)

// Переменные для отображения температуры и влажности
bool showTemp = false; // Флаг для отображения температуры
bool showHumidity = false; // Флаг для отображения влажности
unsigned long sensorTimer = 0; // Таймер для обновления данных с датчика

void setup() {
Serial.begin(9600);
FastLED.addLeds<WS2812B, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS); // Инициализация ленты
FastLED.setBrightness(currentBrightness); // Установка начальной яркости
pinMode(HUR_PIN, INPUT_PULLUP); // Настройка пинов кнопок
pinMode(MIN_PIN, INPUT_PULLUP);
pinMode(PHOTO_PIN, INPUT); // Фоторезистор
dht.begin(); // Инициализация датчика температуры и влажности
}

// Функция для отображения цифры на ленте
void displayDigit(int digit, int offset, CRGB color) {
for (int i = 0; i < 7; i++) {
if (digits[digit] == 1) {
leds[offset + i] = color; // Включение сегмента
} else {
leds[offset + i] = CRGB::Black; // Выключение сегмента
}
}
}

// Функция для отображения времени
void displayTime(CRGB color) {
// Отображение часов
int hourTens = hours / 10;
int hourOnes = hours % 10;
displayDigit(hourTens, 0, color); // Первый разряд (десятки часов)
displayDigit(hourOnes, 7, color); // Второй разряд (единицы часов)

// Отображение минут
int minuteTens = minutes / 10;
int minuteOnes = minutes % 10;
displayDigit(minuteTens, 14, color); // Третий разряд (десятки минут)
displayDigit(minuteOnes, 21, color); // Четвертый разряд (единицы минут)

// Отображение точек
leds[28] = CRGB::Red; // Первая точка
leds[29] = CRGB::Red; // Вторая точка
}

// Функция для обновления времени
void updateTime() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
minutes++;
if (minutes >= 60) {
minutes = 0;
hours++;
if (hours >= 24) {
hours = 0;
}
isAnimating = true; // Запуск анимации при смене часа
animationStartTime = currentMillis;
}
}
}

// Функция для настройки времени с помощью кнопок
void adjustTime() {
if (digitalRead(HUR_PIN) == LOW) { // Настройка часов
delay(200); // Защита от дребезга
hours++;
if (hours >= 24) {
hours = 0;
}
isAnimating = true; // Запуск анимации
animationStartTime = millis();
}
if (digitalRead(MIN_PIN) == LOW) { // Настройка минут
delay(200); // Защита от дребезга
minutes++;
if (minutes >= 60) {
minutes = 0;
}
isAnimating = true; // Запуск анимации
animationStartTime = millis();
}
}

// Функция для автоматической регулировки яркости
void adjustBrightness() {
int lightLevel = analogRead(PHOTO_PIN); // Чтение значения с фоторезистора
if (lightLevel < 50) { // Если слишком темно, включаем ночной режим
isNightMode = true;
currentBrightness = minBrightness;
} else {
isNightMode = false;
currentBrightness = map(lightLevel, 50, 1023, minBrightness, maxBrightness); // Преобразование значения
}
currentBrightness = constrain(currentBrightness, minBrightness, maxBrightness); // Ограничение диапазона
FastLED.setBrightness(currentBrightness); // Установка яркости
}

// Функция для смены цвета сегментов
void changeSegmentColor() {
currentColorIndex = (currentColorIndex + 1) % 5; // Переключение на следующий цвет
}

// Функция для анимации смены времени
void animateTimeChange() {
if (isAnimating) {
unsigned long currentMillis = millis();
if (currentMillis - animationStartTime < animationDuration) {
// Мигание всеми сегментами
for (int i = 0; i < NUM_LEDS; i++) {
leds = (currentMillis / 100) % 2 == 0 ? CRGB::White : CRGB::Black;
}
} else {
isAnimating = false; // Завершение анимации
}
}
}

// Функция для отображения температуры и влажности
void displaySensorData() {
if (millis() - sensorTimer > 10000) { // Обновление данных каждые 10 секунд
sensorTimer = millis();
float temperature = dht.readTemperature(); // Чтение температуры
float humidity = dht.readHumidity(); // Чтение влажности

if (!isnan(temperature) && !isnan(humidity)) { // Проверка на корректность данных
showTemp = true;
showHumidity = true;
}
}

if (showTemp || showHumidity) {
// Отображение температуры или влажности
// (реализуйте логику отображения, если нужно)
}
}

void loop() {
updateTime(); // Обновление времени
adjustTime(); // Проверка нажатия кнопок
adjustBrightness(); // Регулировка яркости
animateTimeChange(); // Анимация смены времени
displaySensorData(); // Отображение данных с датчика

if (!isAnimating) {
displayTime(segmentColors[currentColorIndex]); // Отображение времени
}

FastLED.show(); // Обновление ленты
delay(100); // Небольшая задержка для стабильности
}
 

zarogoza

✩✩✩✩✩✩✩
29 Авг 2021
4
1
Уважаемые форумчане, кто подскажет в чем проблема. В скетче 1.95 если отключить часы в полной темноте, а после включить, индикация отсутствует, до тех пор пока на датчик не попадет свет.
Вот код регулировки яркости
C++:
void BrightnessCheck() {
  if (setups[4]==0) {                         // если включена адаптивная яркость
  if (millis() - bright_timer > 100) {       // каждые 100 мс
     bright_timer = millis();                // сбросить таймер
     new_bright = map(analogRead(LIGHT_PIN), 0, 1020, LIGHT_MIN, LIGHT_MAX );     // когда темно тускло
     new_bright = constrain(new_bright, LIGHT_MIN, LIGHT_MAX);
     new_bright_f = new_bright_f * coef + new_bright * (1 - coef);
      LEDS.setBrightness(new_bright_f);                                            // установить новую яркость
     }
  }else {new_bright_f = setups[4] * 10;                                          // установить яркость ручную.
  LEDS.setBrightness(new_bright_f);}
}
Как исправить этот баг.
 
Изменено:

kym13

★★✩✩✩✩✩
14 Ноя 2020
617
90
@zarogoza, Сами то часы работают только на дисплей ничего не выводится. Если выставить минимум 9 то часы включаются после отключения электроэнергии но для ночного режима довольно ярко получается.
 
  • Лойс +1
Реакции: zarogoza

zarogoza

✩✩✩✩✩✩✩
29 Авг 2021
4
1
@kym13, Да это я уже понял. Минимум 9 ночью очень ярко. Это как то в коде можно исправить?
в старом методе регулировки такой проблемы не было.
C++:
void BrightnessCheck(){   // Установка яркости по датчику освещенности
  if (setups[4] == 0) brightness = map(analogRead(LIGHT_PIN), 0, 1010, LIGHT_MAX, LIGHT_MIN);  // Когда темно тускло (оригинал)
                                                                                               // при 1023 в полной темноте мерцают диоды
// if (setups[4] == 0) brightness = map(analogRead(LIGHT_PIN), 0, 1023, LIGHT_MIN, LIGHT_MAX); // Когда темно ярко
  else brightness = setups[4] * 10;
  LEDS.setBrightness(brightness);}
 

kym13

★★✩✩✩✩✩
14 Ноя 2020
617
90
@zarogoza, Автор давно не появлялся здесь, он вообще сказал что больше не будет заниматься этим проектом. Надежда только на спецов программистов с этого форума у которых появится желание подправить код.
PS: Попробуйте эти.
 

Вложения

Изменено:

zarogoza

✩✩✩✩✩✩✩
29 Авг 2021
4
1
@kym13, @Sergo_ST, Спасибо Вам большое помогло. Теперь регулировка яркости работает идеально.
В 153 строке поставил
float new_bright, new_bright_f;
Замечательные получились часы. Собрал аж 4 штуки.
Года два назад делал подобные часы с датчиком DHT22 и датчиком освещенности BH1750, но прошивка у тех была, не очень.
Залил прошивку 1.95 с доработками под мои датчики, часы стали просто прекрасные. Еще добавил дополнительный светодиод для запятой.
 

Вложения

  • Лойс +1
Реакции: kym13