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

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

Комментарии

ASM

★★★★✩✩✩
26 Окт 2018
1,485
292
@Вячеслав_45, в моем есть граничные переходы, что выглядит не очень, или делать плавные переходы...
 

Вячеслав_45

★★✩✩✩✩✩
10 Июл 2020
72
64
@ASM, Сделай как у меня в 1.7 там плавно меняется. И просто сделано

@ASM, или я не понял вот это твой
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);}};
А хочеш сделать так
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);}}};
 

ASM

★★★★✩✩✩
26 Окт 2018
1,485
292
Сделай как у меня в 1.7
Сделал, попробую потом отладить яркость, в зависимости от освещения
вроде понял, просто в своем примере делал комфортную яркость под разную освещенность комнаты по показаниям датчика.
а т.к. переписываю код полностью, сравнивая последние скетчи от разных авторов и внедряя в свой, споткнулся в этом месте)
 

bort707

★★★★★★✩
21 Сен 2020
2,859
850
@Вячеслав_45, в моем есть граничные переходы, что выглядит не очень, или делать плавные переходы...
@ASM, в твоем коде из #225 коэффициент неверный, поэтому и переходы неплавные
Подставь там в третьей строчке вместо
C++:
#define coef 0.1
значение 0.9 или 0.8

А так это самый правильный вариант настройки, без резких изменений и ступенек яркости
 

ASM

★★★★✩✩✩
26 Окт 2018
1,485
292
в твоем коде из #225 коэффициент неверный, поэтому и переходы неплавные
в моем коде нет такого) это я ваши привел из темы)
сейчас поставлю по аналогии с Вячеславом, только константы поменяю, почему-то на ночь у них яркая подсветка стоит, а не наоборот)
 

Вячеслав_45

★★✩✩✩✩✩
10 Июл 2020
72
64
@ASM,
почему-то на ночь у них яркая подсветка стоит, а не наоборот)
это зависит о подключения датчика освещенности, значит надо инвертировать. Поменяй местами 0 и 1023 в map и будет норм.
 
  • Лойс +1
Реакции: 14053

ASM

★★★★✩✩✩
26 Окт 2018
1,485
292
Вот, переписал код, используя наработки из этой темы, надеюсь стало лучше)))
Какие будут замечания?) Код в loop буду переделывать на millis, чтобы время удобней было корректировать...
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 0        // Смена цвета ( 0 - никогда, 1 - раз в минуту, 2 - каждые десять минут, 3 - каждый час, 4 - каждые десять часов)
#define max_bright 200        // максимальная яркость (0 - 255)
#define min_bright 10         // минимальная яркость (0 - 255)

#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;

//управление цветом
//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);
};

int GetSecond() {
  tmElements_t Now;
  RTC.read(Now);
  int second = Now.Second;
  return (second);
};

void BrightnessCheck() {
  int sensor_value = analogRead(BRI_PIN);
  if (set_light == 0) brightness = map(sensor_value, 0, 1023, max_bright, min_bright);
  else brightness = set_light * 10;
  LEDS.setBrightness(brightness);
}

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)];    // Случайный цвет из таблицы
      }
      last_digit = digit;
    }
    Now /= 10;
  };
};

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 Dots (boolean Dot_On) {
  leds[56] = (Dot_On) ? ledColor : 0;
  leds[57] = (Dot_On) ? ledColor : 0;
}

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;
      cursor ++;
    }
  }
}

void loop()
{
  BrightnessCheck();
  TimeAdjust();
  TimeToArray();
  FastLED.show();
  delay(1000);
  TimeToArray();
  FastLED.show();
  delay(1000);
  TimeToArray();
  FastLED.show();
  delay(1000);
  TimeToArray();
  FastLED.show();
  delay(1000);
  TimeToArray();
  FastLED.show();
  delay(1000);
  TempToArray();
  FastLED.show();
  delay(2000);
  TempStreetToArray();
  FastLED.show();
  delay(2000);
  PressToArray();
  FastLED.show();
  delay(2000);
}

Попробовал скодить с millis
Первый вариант:
  TTime = millis();
    if (millis() - TTime == 5000)TimeToArray();
    if (millis() - TTime == 7000)TempToArray();
    if (millis() - TTime == 9000)TempStreetToArray();
    if (millis() - TTime == 11000)PressToArray();
никакой реакции)
Второй вариант:
      TTime = millis();
    if (millis() - TTime == 5000) {
      TimeToArray();
      THome = millis();
    }
    if (millis() - THome == 2000) {
      TempToArray();
      TStreet = millis();
    }
    if (millis() - TStreet == 2000) {
      TempStreetToArray();
      TPress = millis();
    }
    if (millis() - TPress == 2000) {
      PressToArray();
    }
показывает показания датчиков одним циклом, куда копать?)
 
Изменено:

Вячеслав_45

★★✩✩✩✩✩
10 Июл 2020
72
64
Привет Всем. Появилась проблема с часам, конкретно с модулем DS3231. Ситуация такая: как то целый день не было света и села батарейка в DS3231 (фикспрайсовская) поставил другую но попалась в руки CR2025, поставил, через несколько дней выдернул и розетки включил снова время сбросилось, открыл часы, CR2025 вздулась. Поставил CR2032. Сейчас при отключении обнуляется время и дата. Какую батарейку не ставил толку нет. Могло ли в DS3231 что нибудь сдохнуть из за вздувшейся 2025? Менять модуль часов еще не пробовал. Погуглил пишут надо ставить аккумулятор 2032, случай не единичный многие пишут что DS3231 не держит время даже при нормальном напряжении на батарейке.
 

ASM

★★★★✩✩✩
26 Окт 2018
1,485
292
@Вячеслав_45, у меня год прожила батарейка, проблема такая, на сколько отключил питание, на столько и отставало время. Померял, напряжение низкое, заменил, сейчас много экспериментов с прошивками, время не отстает) Куда ушел заряд, непонятно, батарею вроде хорошую покупал, сейчас дешевка попалась, поставил ее...
 

Вячеслав_45

★★✩✩✩✩✩
10 Июл 2020
72
64
DS3231 не очень то и прожорливая просто почитав в инете, пишут что на не которых модулях часов нет цепей заряда батарейки, в DS3231 есть, а т.к. видимо рассчитано на CR2032, а я поставил CR2025 поэтому она и вздулась (видимо ток заряда был большой для неё). Поэтому и вопрос, могла ли эта ситуация покалечить саму микросхему DS3231. Заметил ещё когда при отключенном питании вставляешь батарейку на секунду загорается светодиод питания на DS3231 и на Ардуине.
 

bort707

★★★★★★✩
21 Сен 2020
2,859
850
пишут что на не которых модулях часов нет цепей заряда батарейки
а там должен быть заряд? Это же батарейка, ее заряжать нельзя.
Народ массово выпаивает анти-зарядный диод... хотя он там совсем не зря стоит
 

Вячеслав_45

★★✩✩✩✩✩
10 Июл 2020
72
64
@bort707, вот по этому и рекомендуют ставить аккумулятор, ну или хорошую 2032 она литиевая заряд будет принимать. На своем DS3231 посмотрел к батарейке через резистор и диод подключено 5в. В холостую без батарейки на контакты приходит примерно 4в.
 

maksland

★★★✩✩✩✩
13 Янв 2019
442
103
Omsk
надо убирать тогда цепь подзаряда, в магазинах то обычно батарейки продают
 

Вячеслав_45

★★✩✩✩✩✩
10 Июл 2020
72
64
Вот он как оказывается не знал...

Разница между LIR2032 и CR2032 в том, что CR2032 батарейки, а LIR перезаряжаемые аккумуляторы. И они имеют более высокий рабочий диапазон напряжений, но почти в 10 раз меньшую ёмкость.

CR2032: диапазон напряжений 2000-3300 мВ, ёмкость 200+ мА/ч.
LIR2032: диапазон напряжений 3300-4200 мВ, ёмкость 35 — 45 мА/ч.

Взято тут
 

ASM

★★★★✩✩✩
26 Окт 2018
1,485
292
нашел такую информацию)
 

maksland

★★★✩✩✩✩
13 Янв 2019
442
103
Omsk
ну на 10 лет не хватит но на 5-6 должно хватать
P.S. c платой светодиодов напортачил всё таки я ... буду переделывать :(
 
Изменено:

Somikv

✩✩✩✩✩✩✩
27 Фев 2019
14
7
Устранил замечания. Добавил второй датчик температуры, некоторые настройки часов (все внутри в описании). Как сделать настройка цвета температуры чтоб настраивалась из прошивки или часов.
Добрый день. А нельзя никак температуру с DS3231 брать ?
 

ASM

★★★★✩✩✩
26 Окт 2018
1,485
292
помогите с millis, как правильно реализовать?) #233
 

bort707

★★★★★★✩
21 Сен 2020
2,859
850
C++:
TTime = millis();
if (millis() - TTime == 5000)TimeToArray();
if (millis() - TTime == 7000)TempToArray();
if (millis() - TTime == 9000)TempStreetToArray();
if (millis() - TTime == 11000)PressToArray();
никакой реакции)
а откуда тут может взяться "реакция"? Вы код-то свой читайте...
Вот вы в первой строке приравняли TTime = millis(); и буквально мгновение спустя уже проверяете, не прошло ли уже 5 секунд...
И какой должен быть результат? - конечно не прошло, отвечает ардуина и ничего не делает
 

bort707

★★★★★★✩
21 Сен 2020
2,859
850
т.е. время постоянно обнуляется?
вы сами его обнуляете, судя по коду.
тогда что во втором варианте?
а он чем-то принципиально отличается? начинается с той же строчки

кроме того, вот такое условие
C++:
if (millis() - THome == 2000)
скорее всего никогда не сработает. Подумайте, чтобы это сбылось - нужно чтобы код попал именно на эту строчку ровно в 2000 секунду после записи миллис. Не в 1999-ую и не в 2001-ую, а строго 2000
Никогда так не пишите условия для миллис, пишите так:
C++:
if (millis() - THome >= 2000)