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

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

Комментарии

navangel

✩✩✩✩✩✩✩
11 Янв 2022
13
1
@Leon111_09,у меня 3 на сегмент. Я планировал себе на гараж напротив окна повесить, поэтому нужно что-то влаго-снего-защищенное. Буду экспериментировать с фанерой, стеклом и металлом.
 

lafrof

✩✩✩✩✩✩✩
19 Янв 2022
18
2
ДОБРЫЙ ДЕНЬ!!! Люди добрые подскажите пожалуйста, собираю часы уже задалбался . Во всех скетчах используются другие датчики (у меня имеется nano/DHT11/ds1307/DS18B20) не осталось ли у кого ни будь старых скетчей для этих датчиков, всю бошку себе сломал. Скачал пару десятков скетчей и они все идут на новых датчиках, ковырялся в них ни чего не работает. Или подскажите как переделать (не нужны не какие свистоперделки) часы, температура, снаружи внутри и всё. Заранее ОГРОМНОЕ СПАСИБО!!!!!!!!!!!
 

ASM

★★★★✩✩✩
26 Окт 2018
1,515
294
@lafrof, библиотеки нужно заменить, примеров с ds1307 в Гугл полно, немного подкорректировать код только) скетчи с ним должны быть в теме)
 

lafrof

✩✩✩✩✩✩✩
19 Янв 2022
18
2
@ASM, мне ваши часики понравились которые на ардуино на yotube увидел, хотел их воплотить ни чего не получается куча библиотек скачано компилятор постаянно на что то ругается.
 

ASM

★★★★✩✩✩
26 Окт 2018
1,515
294
Examples→RTClib→ds1307
Пример там описан, остальное по аналогии.
Думаю немного упорства и всё заработает.
Также необходимо определиться с прошивкой.
Хотели на все прошивки добавить ссылки в шапку, администрация мне ответила, что не может этого сделать) Обращайтесь к автору... Которого походу давно на форуме нет... Проще создать новую тему)

@lafrof, смотря на что ругается, надо на это смотреть
 

lafrof

✩✩✩✩✩✩✩
19 Янв 2022
18
2
я делал на кухню большие часы года 4 назад, неделю с ними ковырялся но победил. Единственое что меня в них не устроило что минус не показывают +1 или -1 не понятно, а так всё норм с ними
 

ASM

★★★★✩✩✩
26 Окт 2018
1,515
294
@lafrof, значит надо подправить код, сложности с минусом нет. В скетчах пример есть. Если температура минус, показать символ минус) В последнем скетче моём точно должно быть это. Чуть выше была ссылка, там всё расписано в коде.
 

lafrof

✩✩✩✩✩✩✩
19 Янв 2022
18
2
@ASM, это было давно, скетч уже не найду, там тоже люди много помогали. в вашем скетче я пробовал менять там тоже ругается то на 1307 то на BMP
 

ASM

★★★★✩✩✩
26 Окт 2018
1,515
294
@lafrof, вот пример с ds1302 и с минусом температуры)
C++:
/////////////////////////////////////////////
//#include <DS3232RTC.h> // библиотека часов из менеджера библиотек
#include <iarduino_RTC.h>                                   // Подключаем библиотеку iarduino_RTC для работы с модулями реального времени.
iarduino_RTC Now(RTC_DS1302, 10, 12, 11);
#include <FastLED.h>   // библиотека светодиодов из менеджера библиотек
#include <microDS18B20.h> // библиотека уличного датчика https://github.com/AlexGyver/GyverLibs/releases/download/microDS18B20/microDS18B20.zip
MicroDS18B20 sensors(2);  // присваиваем уличному датчику переменную sensors на 2 PIN
#include <iarduino_Pressure_BMP.h>  // библиотека Adafruit_BMP280_Library датчика BMP280 из менеджера библиотек
iarduino_Pressure_BMP sensor(0x76); // присваиваем датчику BMP280 переменную 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 255        // максимальная яркость (0 - 255)
#define min_bright 10         // минимальная яркость (0 - 255)
#define bright_constant 1023  // константа усиления от внешнего света (0 - 1023), чем МЕНЬШЕ константа, тем "резче" будет прибавляться яркость
#define coef 0.4              // коэффициент фильтра (0.0 - 1.0), чем больше - тем медленнее меняется яркость
#define auto_bright 1         // автоматическая подстройка яркости от уровня внешнего освещения (1 - включить, 0 - выключить)
/////////////////////////////////////////////
#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];  // определение СД ленты
uint8_t  digits[] = { // определяем символы для отображения
// код начинается с 0b0, далее идут 7 цифр, каждая цифра это номер фрагмента, 1 - включен, 0- отключен
// далее указан получающийся символ и порядковый номер в массиве
  0b00111111,     // Символ 0          0
  0b00100001,     // Символ 1          1
  0b01110110,     // Символ 2          2
  0b01110011,     // Символ 3          3
  0b01101001,     // Символ 4          4
  0b01011011,     // Символ 5          5
  0b01011111,     // Символ 6          6
  0b00110001,     // Символ 7          7
  0b01111111,     // Символ 8          8
  0b01111011,     // Символ 9          9
  0b01111000,     // Символ * градус  10
  0b00011110,     // Символ C         11
  0b00000000,     // Без символа      12
  0b01000000      // Символ -         13
};
/////////////////////////////////////////////
bool Dot = true;    // переменная для точек
int last_digit = 0; // последний символ равен нулю
byte set_light;     // переменная для освещенности
byte brightness;    // переменная для освещенности
int new_bright, new_bright_f; // переменная для освещенности
unsigned long bright_timer, off_timer; // переменная для освещенности
/////////////////////////////////////////////
//управление цветом
//int ledColor = 0x00FFFF;    // цвет в hex
//long ledColor = CRGB::Blue; // цвет в hex
CRGB ledColor = CRGB::Blue;   // цвет в hex
// массив цветов, для рандом при включенном режиме cylon(); ledColor =  ColorTable[random(16)];
CRGB 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);
  Now.begin();
//  Now.settime(0,45,15,13,3,21,6);
  FastLED.addLeds<WS2812B, LED_PIN, RGB>(leds, NUM_LEDS); // подключение ленты
  pinMode(MIN_PIN, INPUT_PULLUP); // кнопка минутная
  pinMode(HUR_PIN, INPUT_PULLUP); // кнопка часовая
  //ниже я вывел питание на отдельные пины, вы можете питать напрямую от источника питания :)
  pinMode(A3, OUTPUT);   // контакт GND барометра
  digitalWrite(A3, LOW); // подача земли на барометр
  pinMode(9, OUTPUT);    // контакт VCC датчика осв
  digitalWrite(9, HIGH); // подача питания на датчик осв
  pinMode(8, OUTPUT);    // контакт VCC DS1302
  digitalWrite(8, HIGH); // подача питания на DS1302
}
/////////////////////////////////////////////
int GetTime() { // функция времени
//  tmElements_t Now;
Now.gettime();
//  RTC.read(Now);
  int hour = Now.Hours;
  int minute = Now.minutes;
  int second = Now.seconds;
  Serial.print(hour);   Serial.print(":");  // вывод часов
  Serial.print(minute); Serial.print(":");  // вывод минут
  Serial.print(second); Serial.println(""); // вывод секунд
  Dot = second % 2; // точки мигают раз в сек
  return (hour * 100 + minute);
};
/////////////////////////////////////////////
void BrightnessCheck() { // функция освещенности
  static uint32_t last_br = millis();
  if ((millis() - last_br) < 10000) return;
  last_br = millis();
  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(); // получаем время
  boolean Dots = true; // точки
  if (Dot == 0) Dots = false; else Dots = true;
  if (Dots) { // показ точек
  for (uint8_t i = 0; i < DOTS_NUM; i++) {
leds[(LEDS_IN_SEGMENT * 14)+ i] = ledColor;
}
  }
  else {
    Dots_off(); // выключение точек
    }
  for (int i = 1; i <= 4; i++) { // 4 сегмента
    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[12], cursor); // если впереди ноль, то выключаем его, например 01:23 будет как 1:23
    else
      Digit(digits[digit], cursor);                     // иначе показываем символ
    if ( i == COLOR_CHANGE) {                           // как часто менять цвет
      if (digit != last_digit) {
        ledColor =  ColorTable[random(NUM_COLORS)];     // случайный цвет из таблицы
      }
      last_digit = digit;
    }
    Now /= 10;
  };
};
/////////////////////////////////////////////
void Dots_off()  { // отключаем точки принудительно, где не нужны
  for (uint8_t i = 0; i < DOTS_NUM; i++) {
leds[(LEDS_IN_SEGMENT * 14)+ i] = 0x000000;
}
}
/////////////////////////////////////////////
void TempStreetToArray() { // вывод уличной температуры на экран
  sensors.requestTemp(); // опрос датчика уличной температуры
  int celsius = sensors.getTemp(); // чтение уличной температуры
  Serial.println (celsius);

  Dots_off(); // выключаем точки

  Digit(digits[10], (NUM_LEDS - LEDS_IN_SEGMENT * 7)); // символ градуса

  int digit = abs (celsius % 10);
  Digit(digits[digit], (NUM_LEDS - LEDS_IN_SEGMENT * 14));

  digit = abs (celsius / 10);
  if (digit == 0)Digit(digits[12], (NUM_LEDS - LEDS_IN_SEGMENT * 21 - DOTS_NUM)); // если впереди ноль, то выключаем его
  else
    Digit(digits[digit], (NUM_LEDS - LEDS_IN_SEGMENT * 21 - DOTS_NUM)); // иначе показываем как есть

  if (sensors.getTemp() <= -1)Digit(digits[13], (NUM_LEDS - LEDS_IN_SEGMENT * 28 - DOTS_NUM)); // если < или = -1, то показываем -
  else
    Digit(digits[12], (NUM_LEDS - LEDS_IN_SEGMENT * 28 - DOTS_NUM)); // иначе выключаем 1 сегмент
};
/////////////////////////////////////////////
void TempToArray() { // вывод температуры с датчика BMP280 на экран
  sensor.begin();
  int celsius = sensor.temperature - 1; // считываем датчик, датчик за часами, часы на стене, там температура чуть выше, корректировка минус 1
  Serial.println (celsius);

  Dots_off(); // выключаем точки
  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[12], (NUM_LEDS - LEDS_IN_SEGMENT * 21 - DOTS_NUM)); // если впереди ноль, то выключаем его
  else
    Digit(digits[digit], (NUM_LEDS - LEDS_IN_SEGMENT * 21 - DOTS_NUM)); // иначе показываем как есть
    
  Digit(digits[12], (NUM_LEDS - LEDS_IN_SEGMENT * 28 - DOTS_NUM)); // отключаем 1 сегмент
};
/////////////////////////////////////////////
void PressToArray() { // вывод давления на экран
  sensor.begin();
  int davlenie = sensor.pressure;
  Serial.println (davlenie);

  Dots_off(); // выключаем точки
 
  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[12], (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;
Now.gettime();
//    RTC.read(Now);
    int hour = Now.Hours;
    int minutes = Now.minutes;
    int second = Now.seconds;
    if (buttonH == LOW) {
      if (Now.Hours == 23) {
        Now.Hours = 0;
      }
      else {
        Now.Hours += 1;
      };
    } else {
      if (Now.minutes == 59) {
        Now.minutes = 0;
      }
      else {
        Now.minutes += 1;
      };
    };
    //RTC.write(Now);
    Now.settime(0, minutes, hour);
  }
}
/////////////////////////////////////////////
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 : CRGB (0, 0, 0);
      cursor ++;
    }
  }
}
/////////////////////////////////////////////
void loop() {
  BrightnessCheck();
  TimeAdjust();
  static bool TempShow = true; // флаг для температуры в помещении
  static bool TempSShow = true; // флаг для температуры на улице
  static bool PressShow = true; // флаг для давления
  uint32_t tmrall = millis() % 12000 / 1000;
  static uint32_t tmrall_old = 10000;
  if (tmrall_old != tmrall)
  {
    tmrall_old = tmrall;
    if (tmrall < 6)
    {
      TimeToArray();
      TempShow = true;
      TempSShow = true;
      PressShow = true;
    }
    else if (tmrall < 8)
    {
      if (TempShow)
      {
        TempToArray();
        TempShow = false;
      }
    }
    else if (tmrall < 10)
    {
      if (TempSShow)
      {
        TempStreetToArray();
        TempSShow = false;
      }
    }
    else
    {
      if (PressShow)
      {
        PressToArray();
        PressShow = false;
      }
    }
    FastLED.show(); // команда для включения светодиодов
  };
}
/////////////////////////////////////////////
 
  • Лойс +1
Реакции: lafrof

lafrof

✩✩✩✩✩✩✩
19 Янв 2022
18
2
@lafrof, @ASM, я уже готов плюнуть на комнатную температуру, уличная с минусом и часы ВСЁ. я помню с прошлыми часами переписывал весь масив с количеством светиков мне тогда разжевали как это сделать, сейчас честно уже ни чего не помню. Думал сделаю ха выходные, не тут то было.
 

bort707

★★★★★★✩
21 Сен 2020
2,898
860
@lafrof, раз первая "двойка" показывается верно, значит с этими массивами все ОК и искать ошибку надо в другом месте.

А вообще, выкладывать код фоткой с телефона - этоиздевательство над отвечающим.
 
Изменено:

lafrof

✩✩✩✩✩✩✩
19 Янв 2022
18
2
@bort707,
C++:
#include <DS1307.h>

#include <iarduino_RTC.h>

/////////////////////////////////////////////
#include <DS1307.h> // библиотека часов из менеджера библиотек
#include <iarduino_RTC.h>                                   // Подключаем библиотеку iarduino_RTC для работы с модулями реального времени.
iarduino_RTC Now(RTC_DS1307);
#include <FastLED.h>   // библиотека светодиодов из менеджера библиотек
#include <microDS18B20.h> // библиотека уличного датчика https://github.com/AlexGyver/GyverLibs/releases/download/microDS18B20/microDS18B20.zip
MicroDS18B20 sensors(2);  // присваиваем уличному датчику переменную sensors на 2 PIN
#include <iarduino_Pressure_BMP.h>  // библиотека Adafruit_BMP280_Library датчика BMP280 из менеджера библиотек
iarduino_Pressure_BMP sensor(0x76); // присваиваем датчику BMP280 переменную sensor на адресе (0x76)
/////////////////////////////////////////////
#define LEDS_IN_SEGMENT 1     // задаём сколько у нас светодиодов в сегменте
#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 255        // максимальная яркость (0 - 255)
#define min_bright 10         // минимальная яркость (0 - 255)
#define bright_constant 1023  // константа усиления от внешнего света (0 - 1023), чем МЕНЬШЕ константа, тем "резче" будет прибавляться яркость
#define coef 0.4              // коэффициент фильтра (0.0 - 1.0), чем больше - тем медленнее меняется яркость
#define auto_bright 1         // автоматическая подстройка яркости от уровня внешнего освещения (1 - включить, 0 - выключить)
/////////////////////////////////////////////
#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];  // определение СД ленты
uint8_t  digits[] = { // определяем символы для отображения
// код начинается с 0b0, далее идут 7 цифр, каждая цифра это номер фрагмента, 1 - включен, 0- отключен
// далее указан получающийся символ и порядковый номер в массиве
  0b00111111,     // Символ 0          0
  0b00100001,     // Символ 1          1
  0b01110110,     // Символ 2          2
  0b01110011,     // Символ 3          3
  0b01101001,     // Символ 4          4
  0b01011011,     // Символ 5          5
  0b01011111,     // Символ 6          6
  0b00110001,     // Символ 7          7
  0b01111111,     // Символ 8          8
  0b01111011,     // Символ 9          9
  0b01111000,     // Символ * градус  10
  0b00011110,     // Символ C         11
  0b00000000,     // Без символа      12
  0b01000000      // Символ -         13
};
/////////////////////////////////////////////
bool Dot = true;    // переменная для точек
int last_digit = 0; // последний символ равен нулю
byte set_light;     // переменная для освещенности
byte brightness;    // переменная для освещенности
int new_bright, new_bright_f; // переменная для освещенности
unsigned long bright_timer, off_timer; // переменная для освещенности
/////////////////////////////////////////////
//управление цветом
//int ledColor = 0x00FFFF;    // цвет в hex
//long ledColor = CRGB::Blue; // цвет в hex
CRGB ledColor = CRGB::Blue;   // цвет в hex
// массив цветов, для рандом при включенном режиме cylon(); ledColor =  ColorTable[random(16)];
CRGB 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);
  Now.begin();
  Now.settime(0,14,22,23,1,22,6);
  FastLED.addLeds<WS2812B, LED_PIN, RGB>(leds, NUM_LEDS); // подключение ленты
  pinMode(MIN_PIN, INPUT_PULLUP); // кнопка минутная
  pinMode(HUR_PIN, INPUT_PULLUP); // кнопка часовая
  //ниже я вывел питание на отдельные пины, вы можете питать напрямую от источника питания :)
  pinMode(A3, OUTPUT);   // контакт GND барометра
  digitalWrite(A3, LOW); // подача земли на барометр
  pinMode(9, OUTPUT);    // контакт VCC датчика осв
  digitalWrite(9, HIGH); // подача питания на датчик осв
  pinMode(8, OUTPUT);    // контакт VCC DS1302
  digitalWrite(8, HIGH); // подача питания на DS1302
}
/////////////////////////////////////////////
int GetTime() { // функция времени
//  tmElements_t Now;
Now.gettime();
//  RTC.read(Now);
  int hour = Now.Hours;
  int minute = Now.minutes;
  int second = Now.seconds;
  Serial.print(hour);   Serial.print(":");  // вывод часов
  Serial.print(minute); Serial.print(":");  // вывод минут
  Serial.print(second); Serial.println(""); // вывод секунд
  Dot = second % 2; // точки мигают раз в сек
  return (hour * 100 + minute);
};
/////////////////////////////////////////////
void BrightnessCheck() { // функция освещенности
  static uint32_t last_br = millis();
  if ((millis() - last_br) < 10000) return;
  last_br = millis();
  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(); // получаем время
  boolean Dots = true; // точки
  if (Dot == 0) Dots = false; else Dots = true;
  if (Dots) { // показ точек
  for (uint8_t i = 0; i < DOTS_NUM; i++) {
leds[(LEDS_IN_SEGMENT * 14)+ i] = ledColor;
}
  }
  else {
    Dots_off(); // выключение точек
    }
  for (int i = 1; i <= 4; i++) { // 4 сегмента
    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[12], cursor); // если впереди ноль, то выключаем его, например 01:23 будет как 1:23
    else
      Digit(digits[digit], cursor);                     // иначе показываем символ
    if ( i == COLOR_CHANGE) {                           // как часто менять цвет
      if (digit != last_digit) {
        ledColor =  ColorTable[random(NUM_COLORS)];     // случайный цвет из таблицы
      }
      last_digit = digit;
    }
    Now /= 10;
  };
};
/////////////////////////////////////////////
void Dots_off()  { // отключаем точки принудительно, где не нужны
  for (uint8_t i = 0; i < DOTS_NUM; i++) {
leds[(LEDS_IN_SEGMENT * 14)+ i] = 0x000000;
}
}
/////////////////////////////////////////////
void TempStreetToArray() { // вывод уличной температуры на экран
  sensors.requestTemp(); // опрос датчика уличной температуры
  int celsius = sensors.getTemp(); // чтение уличной температуры
  Serial.println (celsius);

  Dots_off(); // выключаем точки

  Digit(digits[10], (NUM_LEDS - LEDS_IN_SEGMENT * 7)); // символ градуса

  int digit = abs (celsius % 10);
  Digit(digits[digit], (NUM_LEDS - LEDS_IN_SEGMENT * 14));

  digit = abs (celsius / 10);
  if (digit == 0)Digit(digits[12], (NUM_LEDS - LEDS_IN_SEGMENT * 21 - DOTS_NUM)); // если впереди ноль, то выключаем его
  else
    Digit(digits[digit], (NUM_LEDS - LEDS_IN_SEGMENT * 21 - DOTS_NUM)); // иначе показываем как есть

  if (sensors.getTemp() <= -1)Digit(digits[13], (NUM_LEDS - LEDS_IN_SEGMENT * 28 - DOTS_NUM)); // если < или = -1, то показываем -
  else
    Digit(digits[12], (NUM_LEDS - LEDS_IN_SEGMENT * 28 - DOTS_NUM)); // иначе выключаем 1 сегмент
};
/////////////////////////////////////////////
void TempToArray() { // вывод температуры с датчика BMP280 на экран
  sensor.begin();
  int celsius = sensor.temperature - 1; // считываем датчик, датчик за часами, часы на стене, там температура чуть выше, корректировка минус 1
  Serial.println (celsius);

  Dots_off(); // выключаем точки
  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[12], (NUM_LEDS - LEDS_IN_SEGMENT * 21 - DOTS_NUM)); // если впереди ноль, то выключаем его
  else
    Digit(digits[digit], (NUM_LEDS - LEDS_IN_SEGMENT * 21 - DOTS_NUM)); // иначе показываем как есть
    
  Digit(digits[12], (NUM_LEDS - LEDS_IN_SEGMENT * 28 - DOTS_NUM)); // отключаем 1 сегмент
};
/////////////////////////////////////////////
void PressToArray() { // вывод давления на экран
  sensor.begin();
  int davlenie = sensor.pressure;
  Serial.println (davlenie);

  Dots_off(); // выключаем точки
 
  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[12], (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;
Now.gettime();
//    RTC.read(Now);
    int hour = Now.Hours;
    int minutes = Now.minutes;
    int second = Now.seconds;
    if (buttonH == LOW) {
      if (Now.Hours == 23) {
        Now.Hours = 0;
      }
      else {
        Now.Hours += 1;
      };
    } else {
      if (Now.minutes == 59) {
        Now.minutes = 0;
      }
      else {
        Now.minutes += 1;
      };
    };
    //RTC.write(Now);
    Now.settime(0, minutes, hour);
  }
}
/////////////////////////////////////////////
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 : CRGB (0, 0, 0);
      cursor ++;
    }
  }
}
/////////////////////////////////////////////
void loop() {
  BrightnessCheck();
  TimeAdjust();
  static bool TempShow = true; // флаг для температуры в помещении
  static bool TempSShow = true; // флаг для температуры на улице
  static bool PressShow = true; // флаг для давления
  uint32_t tmrall = millis() % 12000 / 1000;
  static uint32_t tmrall_old = 10000;
  if (tmrall_old != tmrall)
  {
    tmrall_old = tmrall;
    if (tmrall < 6)
    {
      TimeToArray();
      TempShow = true;
      TempSShow = true;
      PressShow = true;
    }
    else if (tmrall < 8)
    {
      if (TempShow)
      {
        TempToArray();
        TempShow = false;
      }
    }
    else if (tmrall < 10)
    {
      if (TempSShow)
      {
        TempStreetToArray();
        TempSShow = false;
      }
    }
    else
    {
      if (PressShow)
      {
        PressToArray();
        PressShow = false;
      }
    }
    FastLED.show(); // команда для включения светодиодов
  };
}
/////////////////////////////////////////////
 
  • Лойс +1
Реакции: Khaled

bort707

★★★★★★✩
21 Сен 2020
2,898
860
если на вторую позицию вывести другую цифру, например "0" или "8" - все сегменты горят?
 

bort707

★★★★★★✩
21 Сен 2020
2,898
860
я посмотрел код, что-то с ходу не нашел, что может вызывать такое поведение. Если б вы где-то в коде сдвинули индекс на один - то у вас бы все цифры "поехали", а не только вторая
 
  • Лойс +1
Реакции: lafrof

lafrof

✩✩✩✩✩✩✩
19 Янв 2022
18
2
@bort707, извините что сболомутил вас, светик подвёл. Раньше не сталкивался с таким. Висит две гирлянды по 468 светодиодов на окнах. Светик либо работает либо нет.
 

Вложения

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

lafrof

✩✩✩✩✩✩✩
19 Янв 2022
18
2
Добрый день подскажите почему кнопки часы, минуты не работают?

C++:
#include <DS1307.h>

#include <iarduino_RTC.h>

/////////////////////////////////////////////
#include <DS1307.h> // библиотека часов из менеджера библиотек
#include <iarduino_RTC.h>                                   // Подключаем библиотеку iarduino_RTC для работы с модулями реального времени.
iarduino_RTC Now(RTC_DS1307);
#include <FastLED.h>   // библиотека светодиодов из менеджера библиотек
#include <microDS18B20.h> // библиотека уличного датчика https://github.com/AlexGyver/GyverLibs/releases/download/microDS18B20/microDS18B20.zip
MicroDS18B20 sensors(2);  // присваиваем уличному датчику переменную sensors на 2 PIN
#include <iarduino_Pressure_BMP.h>  // библиотека Adafruit_BMP280_Library датчика BMP280 из менеджера библиотек
iarduino_Pressure_BMP sensor(0x77); // присваиваем датчику BMP280 переменную sensor на адресе (0x76)
/////////////////////////////////////////////
#define LEDS_IN_SEGMENT 1     // задаём сколько у нас светодиодов в сегменте
#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 255        // максимальная яркость (0 - 255)
#define min_bright 10         // минимальная яркость (0 - 255)
#define bright_constant 1023  // константа усиления от внешнего света (0 - 1023), чем МЕНЬШЕ константа, тем "резче" будет прибавляться яркость
#define coef 0.4              // коэффициент фильтра (0.0 - 1.0), чем больше - тем медленнее меняется яркость
#define auto_bright 1         // автоматическая подстройка яркости от уровня внешнего освещения (1 - включить, 0 - выключить)
/////////////////////////////////////////////
#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];  // определение СД ленты
uint8_t  digits[] = { // определяем символы для отображения
// код начинается с 0b0, далее идут 7 цифр, каждая цифра это номер фрагмента, 1 - включен, 0- отключен
// далее указан получающийся символ и порядковый номер в массиве
  0b00111111,     // Символ 0          0
  0b00100001,     // Символ 1          1
  0b01110110,     // Символ 2          2
  0b01110011,     // Символ 3          3
  0b01101001,     // Символ 4          4
  0b01011011,     // Символ 5          5
  0b01011111,     // Символ 6          6
  0b00110001,     // Символ 7          7
  0b01111111,     // Символ 8          8
  0b01111011,     // Символ 9          9
  0b01111000,     // Символ * градус  10
  0b00011110,     // Символ C         11
  0b00000000,     // Без символа      12
  0b01000000      // Символ -         13
};
/////////////////////////////////////////////
bool Dot = true;    // переменная для точек
int last_digit = 0; // последний символ равен нулю
byte set_light;     // переменная для освещенности
byte brightness;    // переменная для освещенности
int new_bright, new_bright_f; // переменная для освещенности
unsigned long bright_timer, off_timer; // переменная для освещенности
/////////////////////////////////////////////
//управление цветом
//int ledColor = 0x00FFFF;    // цвет в hex
//long ledColor = CRGB::Blue; // цвет в hex
CRGB ledColor = CRGB::Amethyst;   // цвет в hex
// массив цветов, для рандом при включенном режиме cylon(); ledColor =  ColorTable[random(16)];
CRGB 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);
  Now.begin();
  Now.settime(0,49,23,23,1,22,6);
  FastLED.addLeds<WS2812B, LED_PIN, RGB>(leds, NUM_LEDS); // подключение ленты
  pinMode(MIN_PIN, INPUT_PULLUP); // кнопка минутная
  pinMode(HUR_PIN, INPUT_PULLUP); // кнопка часовая
  //ниже я вывел питание на отдельные пины, вы можете питать напрямую от источника питания :)
  pinMode(A3, OUTPUT);   // контакт GND барометра
  digitalWrite(A3, LOW); // подача земли на барометр
  pinMode(9, OUTPUT);    // контакт VCC датчика осв
  digitalWrite(9, HIGH); // подача питания на датчик осв
  pinMode(8, OUTPUT);    // контакт VCC DS1302
  digitalWrite(8, HIGH); // подача питания на DS1302
}
/////////////////////////////////////////////
int GetTime() { // функция времени
//  tmElements_t Now;
Now.gettime();
//  RTC.read(Now);
  int hour = Now.Hours;
  int minute = Now.minutes;
  int second = Now.seconds;
  Serial.print(hour);   Serial.print(":");  // вывод часов
  Serial.print(minute); Serial.print(":");  // вывод минут
  Serial.print(second); Serial.println(""); // вывод секунд
  Dot = second % 2; // точки мигают раз в сек
  return (hour * 100 + minute);
};
/////////////////////////////////////////////
void BrightnessCheck() { // функция освещенности
  static uint32_t last_br = millis();
  if ((millis() - last_br) < 10000) return;
  last_br = millis();
  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(); // получаем время
  boolean Dots = true; // точки
  if (Dot == 0) Dots = false; else Dots = true;
  if (Dots) { // показ точек
  for (uint8_t i = 0; i < DOTS_NUM; i++) {
leds[(LEDS_IN_SEGMENT * 14)+ i] = ledColor;
}
  }
  else {
    Dots_off(); // выключение точек
    }
  for (int i = 1; i <= 4; i++) { // 4 сегмента
    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[12], cursor); // если впереди ноль, то выключаем его, например 01:23 будет как 1:23
    else
      Digit(digits[digit], cursor);                     // иначе показываем символ
    if ( i == COLOR_CHANGE) {                           // как часто менять цвет
      if (digit != last_digit) {
        ledColor =  ColorTable[random(NUM_COLORS)];     // случайный цвет из таблицы
      }
      last_digit = digit;
    }
    Now /= 10;
  };
};
/////////////////////////////////////////////
void Dots_off()  { // отключаем точки принудительно, где не нужны
  for (uint8_t i = 0; i < DOTS_NUM; i++) {
leds[(LEDS_IN_SEGMENT * 14)+ i] = 0x000000;
}
}
/////////////////////////////////////////////
void TempStreetToArray() { // вывод уличной температуры на экран
  sensors.requestTemp(); // опрос датчика уличной температуры
  int celsius = sensors.getTemp(); // чтение уличной температуры
  Serial.println (celsius);

  Dots_off(); // выключаем точки

  Digit(digits[10], (NUM_LEDS - LEDS_IN_SEGMENT * 7)); // символ градуса

  int digit = abs (celsius % 10);
  Digit(digits[digit], (NUM_LEDS - LEDS_IN_SEGMENT * 14));

  digit = abs (celsius / 10);
  if (digit == 0)Digit(digits[12], (NUM_LEDS - LEDS_IN_SEGMENT * 21 - DOTS_NUM)); // если впереди ноль, то выключаем его
  else
    Digit(digits[digit], (NUM_LEDS - LEDS_IN_SEGMENT * 21 - DOTS_NUM)); // иначе показываем как есть

  if (sensors.getTemp() <= -1)Digit(digits[13], (NUM_LEDS - LEDS_IN_SEGMENT * 28 - DOTS_NUM)); // если < или = -1, то показываем -
  else
    Digit(digits[12], (NUM_LEDS - LEDS_IN_SEGMENT * 28 - DOTS_NUM)); // иначе выключаем 1 сегмент
};
/////////////////////////////////////////////
void TempToArray() { // вывод температуры с датчика BMP280 на экран
  sensor.begin();
  int celsius = sensor.temperature - 1; // считываем датчик, датчик за часами, часы на стене, там температура чуть выше, корректировка минус 1
  Serial.println (celsius);

  Dots_off(); // выключаем точки
  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[12], (NUM_LEDS - LEDS_IN_SEGMENT * 21 - DOTS_NUM)); // если впереди ноль, то выключаем его
  else
    Digit(digits[digit], (NUM_LEDS - LEDS_IN_SEGMENT * 21 - DOTS_NUM)); // иначе показываем как есть
    
  Digit(digits[12], (NUM_LEDS - LEDS_IN_SEGMENT * 28 - DOTS_NUM)); // отключаем 1 сегмент
};
/////////////////////////////////////////////
void PressToArray() { // вывод давления на экран
  sensor.begin();
  int davlenie = sensor.pressure;
  Serial.println (davlenie);

  Dots_off(); // выключаем точки
 
  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[12], (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;
Now.gettime();
//    RTC.read(Now);
    int hour = Now.Hours;
    int minutes = Now.minutes;
    int second = Now.seconds;
    if (buttonH == LOW) {
      if (Now.Hours == 23) {
        Now.Hours = 0;
      }
      else {
        Now.Hours += 1;
      };
    } else {
      if (Now.minutes == 59) {
        Now.minutes = 0;
      }
      else {
        Now.minutes += 1;
      };
    };
    //RTC.write(Now);
    Now.settime(0, minutes, hour);
  }
}
/////////////////////////////////////////////
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 : CRGB (0, 0, 0);
      cursor ++;
    }
  }
}
/////////////////////////////////////////////
void loop() {
  BrightnessCheck();
  TimeAdjust();
  static bool TempShow = true; // флаг для температуры в помещении
  static bool TempSShow = true; // флаг для температуры на улице
  static bool PressShow = true; // флаг для давления
  uint32_t tmrall = millis() % 12000 / 1000;
  static uint32_t tmrall_old = 10000;
  if (tmrall_old != tmrall)
  {
    tmrall_old = tmrall;
    if (tmrall < 6)
    {
      TimeToArray();
      TempShow = true;
      TempSShow = true;
      PressShow = true;
    }
    else if (tmrall < 8)
    {
      if (TempShow)
      {
        TempToArray();
        TempShow = false;
      }
    }
    else if (tmrall < 10)
    {
      if (TempSShow)
      {
        TempStreetToArray();
        TempSShow = false;
      }
    }
    else
    {
      if (PressShow)
      {
        PressToArray();
        PressShow = false;
      }
    }
    FastLED.show(); // команда для включения светодиодов
  };
}
/////////////////////////////////////////////