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

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

Комментарии

bort707

★★★★★★✩
21 Сен 2020
2,895
860
@ASM, выложите текущий код полностью, подозреваю что проблема совсем не в этой строчке
 

ASM

★★★★✩✩✩
26 Окт 2018
1,514
294
@bort707, немногим выше весь код был на обозрение)
C++:
#include <DS3232RTC.h>
#include <FastLED.h>
#include <microDS18B20.h>
MicroDS18B20 sensors(2);
#include <iarduino_Pressure_BMP.h>
iarduino_Pressure_BMP sensor(0x76); //Барометр

#define LEDS_IN_SEGMENT 4     // Задаём сколько у нас светодиодов в сегменте
#define DOTS_NUM 2            // Задаём сколько у нас разделительных точек
#define NUM_LEDS (LEDS_IN_SEGMENT * 28 + DOTS_NUM) // Вычисляем кол-во светодиодов
#define NUM_COLORS 16         // Количество цветов
#define COLOR_CHANGE 1        // Смена цвета ( 0 - никогда, 1 - раз в минуту, 2 - каждые десять минут, 3 - каждый час, 4 - каждые десять часов)
#define max_bright 200        // максимальная яркость (0 - 255)
#define min_bright 10         // минимальная яркость (0 - 255)
#define bright_constant 1000  // константа усиления от внешнего света (0 - 1023), чем МЕНЬШЕ константа, тем "резче" будет прибавляться яркость
#define coef 0.4              // коэффициент фильтра (0.0 - 1.0), чем больше - тем медленнее меняется яркость
int new_bright, new_bright_f;
#define auto_bright 1         // автоматическая подстройка яркости от уровня внешнего освещения (1 - включить, 0 - выключить)
unsigned long bright_timer, off_timer;


#define COLOR_ORDER GRB  // Тип ленты
#define LED_PIN 6  // Пин дата от ленты
#define MIN_PIN 5  // Пин минутной кнопки
#define HUR_PIN 4  // Пин часовой кнопки
#define BRI_PIN A0 // PIN фоторезистора

CRGB leds[NUM_LEDS]; // Define LEDs strip

uint8_t  digits[] = {
  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
  0b00011110,     // Digit C         11
  0b01111100,     // Digit P         12
  0b00000000,     // Blank           13
  0b01000000      // Digit -         14
};

bool Dot = true;  //переменная для точек
//bool TempShow = true;  //переменная для температуры
//bool PressShow = true; //переменная для давления
int last_digit = 0;
byte set_light;
byte brightness;
unsigned long Timer;

//управление цветом
//int ledColor = 0x00FFFF; // Color used (in hex)
long ledColor = CRGB::Blue; // Color used (in hex)
//массив цветов, для рандом при включенном режиме cylon(); ledColor =  ColorTable[random(16)];
long ColorTable[NUM_COLORS] = {
  CRGB::Amethyst,
  CRGB::Aqua,
  CRGB::Blue,
  CRGB::Chartreuse,
  CRGB::DarkGreen,
  CRGB::DarkMagenta,
  CRGB::DarkOrange,
  CRGB::DeepPink,
  CRGB::Fuchsia,
  CRGB::Gold,
  CRGB::GreenYellow,
  CRGB::LightCoral,
  CRGB::Tomato,
  CRGB::Salmon,
  CRGB::Red,
  CRGB::Orchid
};

void setup() {
  Serial.begin(9600);
  FastLED.addLeds<WS2812B, LED_PIN, RGB>(leds, NUM_LEDS);
  pinMode(MIN_PIN, INPUT_PULLUP); // Define Minutes adjust button pin
  pinMode(HUR_PIN, INPUT_PULLUP); // Define Hours adjust button pin

  pinMode(A3, OUTPUT); //контакт GND барометра
  digitalWrite(A3, LOW);//подача земли на барометр

  pinMode(9, OUTPUT); //контакт VCC датчика осв
  digitalWrite(9, HIGH);//подача питания на датчик осв
}

int GetTime() {
  tmElements_t Now;
  RTC.read(Now);
  int hour = Now.Hour;
  int minute = Now.Minute;
  int second = Now.Second;
  Serial.print(hour);   Serial.print(":");  // Вывод часов
  Serial.print(minute); Serial.print(":");  // Вывод минут
  Serial.print(second); Serial.println(""); // Вывод секунд
  Dot = second % 2;
  return (hour * 100 + minute);
};

void BrightnessCheck() {
  if (auto_bright) {                         // если включена адаптивная яркость
    if (millis() - bright_timer > 100) {     // каждые 100 мс
      bright_timer = millis();               // сброить таймер
      new_bright = map(analogRead(BRI_PIN), 0, bright_constant, max_bright, min_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);      // установить новую яркость
    }
  }
};

void TimeToArray(){
  int Now = GetTime(); // Получаем время
  Dots(Dot);
  for (int i = 1; i <= 4; i++) {
    int digit = Now % 10; // Получаем последнюю цифру в времени
    int cursor = NUM_LEDS - i * LEDS_IN_SEGMENT * 7;
    if (i > 2) {
      cursor -= DOTS_NUM;
    }
    if ( i == 4 & digit == 0)Digit(digits[13], cursor); //Если впереди ноль, то выключаем его
    else
      Digit(digits[digit], cursor);                     //Иначе показываем символ
    if ( i == COLOR_CHANGE) {                           //Как часто менять цвет
      if (digit != last_digit) {
//        ledColor =  ColorTable[random(NUM_COLORS)];    // Случайный цвет из таблицы
//        cylon();
//randomcolor();
      }
      last_digit = digit;
 //     randomcolor();
    }
    Now /= 10;
  };
};

void Dots (boolean Dot_On) {
  leds[56] = (Dot_On) ? ledColor : 0;
  leds[57] = (Dot_On) ? ledColor : 0;
}

void TempStreetToArray() {
  sensors.requestTemp();
  int celsius = sensors.getTemp();
  Serial.println (celsius);
  Dots(0);
  Digit(digits[10], (NUM_LEDS - LEDS_IN_SEGMENT * 7));
  int digit = abs (celsius % 10);
  Digit(digits[digit], (NUM_LEDS - LEDS_IN_SEGMENT * 14));
  digit = celsius / 10;
  if (digit == 0)Digit(digits[13], (NUM_LEDS - LEDS_IN_SEGMENT * 21 - DOTS_NUM)); //Если впереди ноль, то выключаем его
  else
    Digit(digits[digit], (NUM_LEDS - LEDS_IN_SEGMENT * 21 - 2));
  if (sensors.getTemp() <= -1)Digit(digits[14], (NUM_LEDS - LEDS_IN_SEGMENT * 28 - DOTS_NUM));//если < или = -1, то показываем -
  else
    Digit(digits[13], (NUM_LEDS - LEDS_IN_SEGMENT * 28 - DOTS_NUM)); //иначе выключаем
};

void TempToArray() {
  sensor.begin();
  int celsius = sensor.temperature - 1; // датчик за часами, часы на стене, там температура чуть выше
  Serial.println (celsius);
  Dots(0);
  Digit(digits[10], (NUM_LEDS - LEDS_IN_SEGMENT * 7));
  int digit = abs (celsius % 10);
  Digit(digits[digit], (NUM_LEDS - LEDS_IN_SEGMENT * 14));
  digit = celsius / 10;
  if (digit == 0)Digit(digits[13], (NUM_LEDS - LEDS_IN_SEGMENT * 21 - DOTS_NUM)); //Если впереди ноль, то выключаем его
  else
    Digit(digits[digit], (NUM_LEDS - LEDS_IN_SEGMENT * 21 - DOTS_NUM));
  Digit(digits[13], (NUM_LEDS - LEDS_IN_SEGMENT * 28 - DOTS_NUM)); //отключаем
};

void PressToArray() {
  sensor.begin();
  int davlenie = sensor.pressure;
  Serial.println (davlenie);
  Dots(0);
  int digit = davlenie % 10;
  Digit(digits[digit], (NUM_LEDS - LEDS_IN_SEGMENT * 7));
  digit = davlenie % 100 / 10;
  Digit(digits[digit], (NUM_LEDS - LEDS_IN_SEGMENT * 14));
  digit = davlenie / 100;
  Digit(digits[digit], (NUM_LEDS - LEDS_IN_SEGMENT * 21 - DOTS_NUM));
  Digit(digits[13], (NUM_LEDS - LEDS_IN_SEGMENT * 28 - DOTS_NUM)); //отключаем
};

void TimeAdjust() {
  int buttonH = digitalRead(HUR_PIN);
  int buttonM = digitalRead(MIN_PIN);
  if (buttonH == LOW || buttonM == LOW) {
    delay(200);
    tmElements_t Now;
    RTC.read(Now);
    int hour = Now.Hour;
    int minutes = Now.Minute;
    int second = Now.Second;
    if (buttonH == LOW) {
      if (Now.Hour == 23) {
        Now.Hour = 0;
      }
      else {
        Now.Hour += 1;
      };
    } else {
      if (Now.Minute == 59) {
        Now.Minute = 0;
      }
      else {
        Now.Minute += 1;
      };
    };
    RTC.write(Now);
  }
}

void Digit (uint8_t digit, uint8_t cursor) {
  for (uint8_t mask = 0b01000000; mask > 0; mask = mask >> 1) {
    for (uint8_t i = 0; i < LEDS_IN_SEGMENT; i++) {
      leds[cursor] = (digit & mask) ? ledColor : 0;
//      leds[i] = CHSV(random(0, 256), 255, 255);
      ledColor =  ColorTable[random(NUM_COLORS)];    // Случайный цвет из таблицы
//for (uint8_t k = 0; k < NUM_COLORS-1; k++)ledColor = ColorTable[k];
//Serial.println (ledColor);
//byte   randomcolor = (random(0, 256));
//      randomcolor = (randomcolor + random (16, 240))%256;
//     Serial.print (randomcolor);
//CHSV  ledColor = CHSV (randomcolor, 255, 255);
      cursor ++;
    }
  }
}

void loop(){
  static byte key =0;
  BrightnessCheck();
  TimeAdjust();

    if ((millis() - Timer <= 5000) && (key ==0))
      TimeToArray();FastLED.show();key++;
    if ((millis() - Timer <= 7000) && (millis() - Timer > 5000)&& (key ==1))
      TempToArray();FastLED.show();key++;
    if ((millis() - Timer <= 9000) && (millis() - Timer > 7000)&& (key ==2))
      TempStreetToArray();FastLED.show();key++;
    if ((millis() - Timer <= 11000) && (millis() - Timer > 9000)&& (key ==3))
      PressToArray();FastLED.show();key++;
   if ((millis() - Timer <= 13000) && (millis() - Timer > 11000)&& (key ==4))
      Timer = millis();key==0;
}
 

bort707

★★★★★★✩
21 Сен 2020
2,895
860
@ASM, ты был прав, все упирается в строчку 233
C++:
CHSV  ledColor = CHSV (randomcolor, 255, 255);
убери CHSV в начале строки, этим ты создаешь локальную переменную ledColor , которой и присваивается значение.
Но в строке 235 блок заканчивается и твой новый цвет уничтожается, даже не успев применится ни к одному пикселю

А глобальная переменная ledColor - которая собственно и определяет картинку - не меняется вовсе
 

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

★★★★★★★
14 Авг 2019
4,188
1,280
Москва
Вот.. в зависимости от ситуации выбирается разный цвет. 0 это все равно что черный. Тогда и записать можно так:
leds[cursor] = (digit & mask) ? ledColor : CRGB(0,0,0);
 

ASM

★★★★✩✩✩
26 Окт 2018
1,514
294
@Старик Похабыч, код заработал, разницы не заметил с random table.
Попробую увеличивать цифру 16. никакой разницы...
Вот так выглядит все
 
Изменено:

начинающий

✩✩✩✩✩✩✩
13 Дек 2020
132
9
Всем привет и с наступающим. перечитал всю тему с первой до 12-й страницы несколько раз и запутался окончательно. Прошу модераторов, авторов, соавторов и их помощников по теме и изменениям в конструкции создать в шапке темы для удобства навигации по версиям кодов заголовки или ссылки ведущие к "окончательно доработанным" актуальным версиям кодов в обычном исполнении, в "новогоднем" исполнении и т.д. , так же не лишним было бы там же разместить схему самих часов, что к каким портам подключается, схему и направление соединений отрезков лент ну и т.д., основание: скудные и без того не полные и малоинформативные материалы в источнике на который ссылается автор темы могут просто напросто исчезнуть (может истечь время хранения инфы на ресурсе)... . Ну согласитесь, кому бы от этого стало хуже? Для поиска нужной а главное наиактуальнейшей "искомой" версии темы будь то основной код, либо его версия с изменяемой яркостью, либо уже новогодняя "цветомузыкальная" версия, либо еще какая (из будующих доработок) или какая то из модифицированных схем подключения внешних устройств с отображением и перечислением внесенных изменений.? Ну согласитесь, этож реализовано на всех "великих" форумах, "Тыц" на ссылку и сразу оказался в нужном месте, а так поди разберись, один создал, другой внес изменения, третий еще чегото добавил, потом несколько страниц обсуждений, параллельно появляются "новые задачи" а окончательных доработанных актуальных версий и ссылок на таковые нет ни на одной странице форума. Поверьте при такой иерархии практически не возможно понять где рабочая версия прошивки, где окончательная , где еще какая нибудь, к примеру в последнем сообщении есть фраза: "Код заработал", вот и пойми какой код, ссылка на него ведь не приводится, а на предыдущих 12-ти страницах столько "кодов" , что не возможно сориентироваться к какому из них относится данное сообщение. Мое сообщение не носит никакой критической нагрузки, а скорее наоборот, это крик о помощи и сострадании, не в обиду парни, помогите новичку разобраться в темном мире программирования, сделайте ссылки на "законченные" актуальные версии кодов с описанием их возможностей, разместите пожалуйста схему подключений, и т.д. Буду очень признателен. Всех с наступающим! Спасибо за помощь.
 
Изменено:

suhorukov-p

✩✩✩✩✩✩✩
16 Фев 2019
47
6
@начинающий, Ставь версию Clock_1.7_beta_1.ino на странице 9, в ней можно установить два датчика температуры, Схема подключения ардуинки на странице 6 от 2 августа 2019 года, схема расключения адресной ленты на 7 странице. Если что не понятно пиши, попробуем разобраться.
 

начинающий

✩✩✩✩✩✩✩
13 Дек 2020
132
9
@начинающий, Ставь версию Clock_1.7_beta_1.ino на странице 9, в ней можно установить два датчика температуры, Схема подключения ардуинки на странице 6 от 2 августа 2019 года, схема расключения адресной ленты на 7 странице. Если что не понятно пиши, попробуем разобраться.
Спасибо Вам огромное за ответ. Вот посмотрел скетч и окончательно запутался, в представленных демо видео о работе часов фигурировали такие показания как: время, т1, т2, и давление а в скетче на который дана ссылка даже упоминание об измерении давления не нашел, искал по двум критериям "давл" и "pres" так что выходит, это всетаки не доработанная версия прошивки, так где взять финальную, со всеми измеряемыми и отображаемыми параметрами, существует ли вообще такая, вероятно что да, видео откуда то же взялось?
 
Изменено:

suhorukov-p

✩✩✩✩✩✩✩
16 Фев 2019
47
6
Спасибо Вам огромное за ответ. Вот посмотрел скетч и окончательно запутался, в представленных демо видео о работе часов фигурировали такие показания как: время, т1, т2, и давление а в скетче на который дана ссылка даже упоминание об измерении давления не нашел, искал по двум критериям "давл" и "pres" так что выходит, это всетаки не доработанная версия прошивки, так где взять финальную, со всеми измеряемыми и отображаемыми параметрами, существует ли вообще такая, вероятно что да, видео откуда то же взялось?
Тут только с датчиками температуры, где то в начале была тема про давление, но её не разворачивали
 

ASM

★★★★✩✩✩
26 Окт 2018
1,514
294
@suhorukov-p, поделился своим скетчем, думаю допилит)
добавлю еще тут, внутренний датчик bmp280 определяет температуру и давление, на улице трубочка ds18b20.
если хочется с bme280, с влажностью, то код минимально изменится, заменить библиотеку.
и по аналогии с давлением добавить влажность и вывести в loop)

добавлю сюда последний вариант с новогодними огоньками, вывод сделал на delay500, millis плохо работает с анимацией)
новогодняя версия на видео чуть выше )
 

Вложения

Изменено:

начинающий

✩✩✩✩✩✩✩
13 Дек 2020
132
9
Спасибо огромное, буду потихоньку "пилить", может че получицца, всех с праздником.
 

next09

✩✩✩✩✩✩✩
26 Янв 2019
6
0
Здравствуйте . Всех с Новым годом ! У кого есть скетч с датчиками DHT11 и DS18B20 , что бы показывали температуру и влажность в комнате , уличную температуру .
 

maksland

★★★✩✩✩✩
13 Янв 2019
462
105
Omsk
маленькие часики, версия платы для одного датчика, косяки все исправил с платами
плата светодиодов и часов с одним датчиком проверена в железе
https://www.tinkercad.com/things/dk49P4S030i корпус
 

Вложения

Изменено:

stranic123

✩✩✩✩✩✩✩
17 Июл 2019
4
0
Ребята подскажите что может быть загрузил в ардуино нано версию часов 1.7 beta у меня 3 светодиода в сегменти выставил количество диодов 86 при включении две разделительные точки мигают где и положено а в сегментах хаос диоды горят в разнобой и разными цветами переход через каждую минуту отображается как и положено при нажатии кнопок также хаос подключено и мрачно все правильно.
 

ASM

★★★★✩✩✩
26 Окт 2018
1,514
294
@stranic123, у меня ответ только такой) неправильно подключены датчики, не считываются они. Попробуй через Serial.print(); и Serial.println(); в мониторе найти что работает неправильно...
 

PareNN

✩✩✩✩✩✩✩
25 Дек 2020
4
0
А можете 1.7 бета переделать для esp8266 , без часов реального времени - по NTP.
 

stranic123

✩✩✩✩✩✩✩
17 Июл 2019
4
0
Привет подскажи почему в версии часов 1.7 датчик температуры не определяется а когда загружаю демо тест в ардуино то датчик определяется
 

Вложения

bort707

★★★★★★✩
21 Сен 2020
2,895
860
Привет подскажи почему в версии часов 1.7 датчик температуры не определяется а когда загружаю демо тест в ардуино то датчик определяется
может потому что в коде часов работа с датчиком неполная? - где например в коде request_Temp() ?