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

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

Комментарии

Вячеслав_45

★★✩✩✩✩✩
10 Июл 2020
72
64
Устранил замечания. Добавил второй датчик температуры, некоторые настройки часов (все внутри в описании). Как сделать настройка цвета температуры чтоб настраивалась из прошивки или часов.
 

Вложения

bort707

★★★★★★✩
21 Сен 2020
3,046
909
@bort707, на заметку строка
led_color = color_table[set_color - 1];
при set_color = 0 ошибку не вызывает, просто led_color = последнему элементу массива color_table [ ]
Вячеслав это Вы сами придумали или как?
Вот, запустите тест и убедитесь, что это чушь:
C++:
byte a[] = {11,21,31,41,51,55};
void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);
byte element =0;
Serial.print("Element #-1 =");
Serial.println(a[element-1]);
}

void loop() {}
Результат работы программы
C++:
Element #-1 =184
Результат чтения -1(минус первого) значения массива - вовсе не последний элемент (в данном случае 55), а ячейка памяти, расположенная на одно смещение ДО начала массива. Что у вас там будет - неизвестно, у меня вот - 184.
Если вы будете читать color_table[set_color - 1] - будет выдаваться ерунда, а не цвет. А если вы попытаетесь писать по этому адресу - вы с вероятностью 99.99% нарушите структуру данных и завесите программу.

Так что не надо спорить, это именно ошибка. Называется "выход за границу массива" - и это одна из самых грубых ошибок.
 
Изменено:

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

★★★★★★★
14 Авг 2019
4,251
1,297
Москва
Ну в некоторых случаях такое может быть, но скорее эти случаи исключения и хаки. например если в массиве 256 элементов, а указатель имеет тип uint8_t. Но такое чревато...
 

bort707

★★★★★★✩
21 Сен 2020
3,046
909
Ну в некоторых случаях такое может быть, но скорее эти случаи исключения и хаки. например если в массиве 256 элементов, а указатель имеет тип uint8_t. Но такое чревато...
Ну такое использование указателей скорей можно отнести к "грязным хакам", поскольку очень легко можно запутаться самому и получить распашку памяти :)

И да, твое замечание никак не относится к Вячеславу - у него в массиве 20 элементов, так что тут явная ошибка.
 

Вячеслав_45

★★✩✩✩✩✩
10 Июл 2020
72
64
Спорить не буду. Может Ардуино IDEпри компиляции что-то подправляет. Но при такой строке с минусом всё работало и при включении часов первый цвет был последний из массива.
 

bort707

★★★★★★✩
21 Сен 2020
3,046
909
Спорить не буду. Может Ардуино IDEпри компиляции что-то подправляет.
Простите, но Вы сейчас именно спорите. Вы пример-то запускали? Можете попробовать запустить его не в Ардуино, а например в любом компиляторе С на винде или в линуксе.
Ардуино ничего не поправляет, то что я вам пишу - это правила языка С/С++. Никакой "последний элемент" в такой записи не выдается.
 

Вячеслав_45

★★✩✩✩✩✩
10 Июл 2020
72
64
@bort707, я не спорю что это ошибка. Просто написал по факту как было и как работало. Запустить не могу, сижу с телефона.
 

bort707

★★★★★★✩
21 Сен 2020
3,046
909
Просто написал по факту как было и как работало.
эта ошибка вылезет не при любом запуске, а только после полного сброса, когда вы в ЕЕПРОМ пишете нули.
При обычном старте цвет берется из ЕЕПРОМ и все работает.

Кстати, советую так же отрабатывать не только вариант "цвет меньше нуля", а так же "цвет больше числа элементов таблице цветов". В принципе, всяких раз когда вычитаете конфиг откуда-то, в вашем случае из ЕЕПРОМ - необходимо ВСЕ НАСТРОЙКИ проверять на правильность значений.
 

Вячеслав_45

★★✩✩✩✩✩
10 Июл 2020
72
64
Из ЕЕПРОМ цвет берется при каждом старте, и в моих часах там всегда был 0. Работают с февраля этого года вроде, не одного сбоя или зависания, много раз отключались и включались. У меня нет таких познаний объяснить не могу но факт есть факт до версии 1.7 была эта ошибка и всё работало.

Може просто светодиоды отображали такой цвет на выданную им обра-кадабру в 16 битном цвете я незнаю. Надо пробовать на 1.6 вывести в монитор.
 

suhorukov-p

✩✩✩✩✩✩✩
16 Фев 2019
47
6
Всем привет!!! Может для кого-то покажется глупым мой вопрос, уточню, я в программирование не чего не понимаю.
Возможно ли осуществить память настроек?
а то при моей первой сборки часов, я не ставил фоторезистор, и когда произошёл сбой по питанию (отключили свет), то я аж испугался когда часы потухли, думал всё кабздец пришёл, а оказалось, что по умолчании в настройках стоит яркость на 0, и её нужно было добавить, еще цвет стал меняться каждую минуту, и отображении даты и температуры раз в минуту
 

suhorukov-p

✩✩✩✩✩✩✩
16 Фев 2019
47
6
Устранил замечания. Добавил второй датчик температуры, некоторые настройки часов (все внутри в описании). Как сделать настройка цвета температуры чтоб настраивалась из прошивки или часов.
Извините пожалуйста, а эта прошивка на 2 датчика рабочая или бета версия???И там отображение "ДОМ (С)", а "УЛИЦА (0)", как выше на картинках которые , я рисовал??? А то уже ручки чешутся вкрутить второй датчик :)
 

maksland

★★★✩✩✩✩
13 Янв 2019
512
116
Omsk
давайте с одним датчиком допилим прошивку а потом и со вторым
 

suhorukov-p

✩✩✩✩✩✩✩
16 Фев 2019
47
6
давайте с одним датчиком допилим прошивку а потом и со вторым
Так второй датчик не мешает же, в настройках можно выбрать варианты
9. (t) включение датчиков температуры (0 - комнатный, 1 - уличный, 2 - оба)
 

Вячеслав_45

★★✩✩✩✩✩
10 Июл 2020
72
64
В настройках можно выбрать какой символ на какую температуру хоть одинаковые хоть разные. Работать прошивка должна, пока не было возможности проверить. У меня она стоит в часах с одним датчиком. На выходных постараюсь проверить. С одним датчиком если включить на отображение оба то второй показывает 0. Подключение сделал на разные пины, т.к. для меня на данном этапе это было проще и адреса DS18B20 не надо вытягивать.
 
  • Лойс +1
Реакции: andrey170587

Вячеслав_45

★★✩✩✩✩✩
10 Июл 2020
72
64
Всем привет!!! Может для кого-то покажется глупым мой вопрос, уточню, я в программирование не чего не понимаю.
Возможно ли осуществить память настроек?
а то при моей первой сборки часов, я не ставил фоторезистор, и когда произошёл сбой по питанию (отключили свет), то я аж испугался когда часы потухли, думал всё кабздец пришёл, а оказалось, что по умолчании в настройках стоит яркость на 0, и её нужно было добавить, еще цвет стал меняться каждую минуту, и отображении даты и температуры раз в минуту
Можно замкнуть вывод А0 на +5в и будет максимальная яркость
 

ASM

★★★★★✩✩
26 Окт 2018
1,599
311
Конструкторов часов маловато, присоединяюсь к вам.
Мой проект сделан на двп, на нее наклеил ленту, объем цифрам сделал из сэндвич панели, поверх белый лист бумаги.
Корпус из дерева, покрашен акрилом, смесь белой и коричневой.
Основан на коде, который был в интернете, переработан, чтобы работал и добавлены датчики)
Сейчас буду изучать ваш) Позвал @bort707.
часы выглядят так, провода торчат, т.к. занимаюсь ими сейчас.
Тема, в которой я работал
 
Изменено:
  • Лойс +1
Реакции: Старик Похабыч

ASM

★★★★★✩✩
26 Окт 2018
1,599
311
@Вячеслав_45, или у кого его скетч, переделал на 114 диодов, рабочий код у меня такой, проверьте, будет ли работать в ваших вариантах)
C++:
void DigitOut(int cursors, int digit){  // Функция вывода на диоды
  int cursor = cursors;
  for(int k = 0; k <= 6; k++){
    if (digits[digit][k] == 1){
      for(int i = 1; i <= num_point; i++){leds[cursor] = led_color; cursor++;}}
    else if (digits[digit][k] == 0){
      for(int i = 1; i <= num_point; i++){leds[cursor] = 0x000000; cursor++;}
      }}}
 
Изменено:

bort707

★★★★★★✩
21 Сен 2020
3,046
909
@ASM,
посмотрите код из сообщения #104 - это код похожий на ваш, но кардинально переписанный, оптимизированный и с исправленными косяками. Например цифры там заданы всего десятком байт, а не как в вашем коде - огромными массивами.
C++:
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
  0b01111000,     // Digit % знак % из двух частей 13
  0b01000111,     // Digit % знак % из двух частей 14
  0b00000000      // Blank
};
соответнно и выод цифр на ленту тоже короче и проще:
C++:
void BrightDigit (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;
      cursor ++;
    }
  }
}
Код настраивается на любое число диодов в сегменте
 
  • Лойс +1
Реакции: ASM

ASM

★★★★★✩✩
26 Окт 2018
1,599
311
@bort707, я уже смотрел этот скетч, остановлюсь на варианте с Вячеславом, т.к. понимаю что основа сейчас на нём. Буду тогда переводить часы на его. Отображение удалось запустить, уличный датчик прикрутил. Осталось bmp280, в моём варианте на нём куча библиотек, памяти много занимает, надо бы попроще найти. Есть microBME280, но она не считывает данные, хотя адрес тот же. И в коде loop не понятны некоторые действия, на примере датчиков, за что отвечают некоторые строки.

Ребят, в моем скетче часов bmp280 работает исправно, но стоит запустить в новом скетче, где только библиотеки этого датчика, то уже не работает. Пробовал различные примеры из интернета, ни в какую) Может ли быть причиной, что на портах А4 и А5 висят два датчика, bmp280 и ds3231?
Ну и в скетче Вячеслава, заместо домашнего датчика вписал bmp280, он тоже не считывается)
C++:
#include <iarduino_Pressure_BMP.h>
iarduino_Pressure_BMP sensorTempHome(0x76);
---------------------------
        case 20: {            // Режим вывода температуры внутри
      if(temp_flag == false){
              sensorTempHome.begin();
              Serial.println (sensorTempHome.temperature);
----------------------------
-135.36
-135.36
-135.36
 
Изменено:

ASM

★★★★★✩✩
26 Окт 2018
1,599
311
После смены макс и мин работает при свете ярко, без света тускло.
Возможно ли установить плавное изменение света, аналогично моему коду текущей функцией?)
C++:
#define max_bright 100       // максимальная яркость (0 - 255)
#define min_bright 10        // минимальная яркость (0 - 255)
#define bright_constant 1000  // константа усиления от внешнего света (0 - 1023), чем МЕНЬШЕ константа, тем "резче" будет прибавляться яркость
#define coef 0.1             // коэффициент фильтра (0.0 - 1.0), чем больше - тем медленнее меняется яркость
void BrightnessCheck() {
  if (auto_bright) {                         
    if (millis() - bright_timer > 100) {     
      bright_timer = millis();               
      new_bright = map(analogRead(BRI_PIN), 0, bright_constant, min_bright, max_bright);   
      new_bright = constrain(new_bright, max_bright, min_bright);    //поменял местами max и min                     
      new_bright_f = new_bright_f * coef + new_bright * (1 - coef);
      LEDS.setBrightness(new_bright_f);}}};
C++:
void BrightnessCheck(){
  const byte sensorPin = A0; 
  const byte brightnessLow = 5;   // низкая яркость
  const byte brightnessMid = 10;  // низкая яркость
  const byte brightnessHigh = 40; // высокая яркость
  const byte brightnessDay = 60;  // высокая яркость
 int sensorValue = analogRead(sensorPin);
  sensorValue = map(sensorValue, 0, 1023, 0, 255);
  LEDS.setBrightness(sensorValue);
//если в комнате светло, то светит ярче, если мало света, то тусклее, в ночном режиме светит тускло
    if(sensorValue>=221 && sensorValue <=240){LEDS.setBrightness(brightnessHigh);delay(1000);}
        else
    if(sensorValue>=241 && sensorValue <=252){LEDS.setBrightness(brightnessMid);delay(1000);}
        else
    if(sensorValue>=253){LEDS.setBrightness(brightnessLow);delay(1000);}
        else
    if(sensorValue<=220){LEDS.setBrightness(brightnessDay);delay(1000);}};
 

Вячеслав_45

★★✩✩✩✩✩
10 Июл 2020
72
64
@ASM, встав свой код и будет плавно. Тут всего 4 уровня яркости

C++:
if(sensorValue>=101 && sensorValue <=200){LEDS.setBrightness(brightnessHigh);delay(1000);}
        else
    if(sensorValue>=201 && sensorValue <=252){LEDS.setBrightness(brightnessMid);delay(1000);}
        else
    if(sensorValue>=253){LEDS.setBrightness(brightnessLow);delay(1000);}
        else
    if(sensorValue<=100){LEDS.setBrightness(brightnessDay);delay(1000);}};
Ну или хотя бы так