Часы на esp8266 и max7219 + android управление

Тема в разделе "Глядите, что я сделал", создана пользователем IvanUA, 28 авг 2017.

?

Вы повторили это проект?

  1. Нет (просто ознакомился)

    35 голосов
    13,2%
  2. Да, один раз (попробовал)

    111 голосов
    41,9%
  3. Да, не однократно

    123 голосов
    46,4%
Можно выбрать сразу несколько вариантов.
  1. IvanUA

    IvanUA Гуру

    Вот к примеру мой лог с паузой после запроса в 64мс. Период обновления времени 1 минут.
    11:52:30 Отримання cb= 0
    11:52:30 Отримання cb= 48
    i= 1
    24 02 06 E9 00 00 0A 3D
    00 00 09 00 81 86 19 7B
    E8 62 1E 13 79 CA 0A 61
    00 00 00 00 00 00 00 00
    E8 62 22 CE 52 B4 7A D4
    E8 62 22 CE 52 BE CF EE
    11:52:30 Отримання cb= 48
    i= 0
    24 02 06 E9 00 00 0A 3D
    00 00 09 00 81 86 19 7B
    E8 62 1E 13 79 CA 0A 61
    00 00 00 00 00 00 00 00
    E8 62 22 CE 5D AE F5 CC
    E8 62 22 CE 5D BD 85 53
    11:52:30 Отримання cb= 48
    i= 0
    24 02 06 E9 00 00 0A 3D
    00 00 09 01 81 86 19 7B
    E8 62 1E 13 79 CA 0A 61
    00 00 00 00 00 00 00 00
    E8 62 22 CF 2C DC ED 15
    E8 62 22 CF 2C E6 55 3C



    Это только часть с ошибкой, но из полного лога видно что оба раза не было пакета после первого запроса... Возможно времени на ответ не хватает...
    Конечно лучеш использовать вот такой метод.
    Но в моем случае 3 попытки по 1-3 запроса себя оправдывают с головой

    Вот нормальный лог синхронизации
    Код (C++):
    14:56:27  Отримано 48 байт
    14:56:27  Вміст пакету даних.
              24  03  06  E8  00  00  08  22
              00  00  00  16  0A  84  08  A5
              E8  62  4F  32  39  24  9D  36
              00  00  00  00  00  00  00  00
              E8  62  4F  60  60  51  32  F8
              E8  62  4F  60  60  58  54  55
              Спроба #1   15:02:40

    14:56:28  Отримано 48 байт
    14:56:28  Вміст пакету даних.
              24  03  06  E8  00  00  08  22
              00  00  00  16  0A  84  08  A5
              E8  62  4F  32  39  24  9D  36
              00  00  00  00  00  00  00  00
              E8  62  4F  60  77  B3  63  6F
              E8  62  4F  60  77  BA  07  22
              Спроба #2   15:02:40

    14:56:28  Отримано 48 байт
    14:56:28  Вміст пакету даних.
              24  03  06  E8  00  00  08  22
              00  00  00  16  0A  84  08  A5
              E8  62  4F  32  39  24  9D  36
              00  00  00  00  00  00  00  00
              E8  62  4F  60  8D  8A  22  2D
              E8  62  4F  60  8D  8D  8A  7E
              Спроба #3   15:02:40

    15:02:40  Запис часу в пам'ять: {"hour":15,"minute":2,"second":40,"year":2023,"month":7,"day":19}
    15:02:40  19.07.2023 DW=4
              Оновлення часу вдале!!!

    ПС. Обновил приложение - добавил кнопку для синхронизации времени часов с временем телефона.
    ППС. Обновил прошивку - поправил функцию синхронизации с NTP сервером и поправил корректность ручного обновления времени через веб интерфейс.
     
    Последнее редактирование: 19 июл 2023
  2. DiMaro

    DiMaro Нерд

    извиняюсь, часы научились синхронизировать время при бегущей строке на дисплее?
    если так, то код в таком виде и даже с предположительной коррекцией о которой говорите, подтормаживание точно не уберет. там не подтормаживание а фризы гарантированны

    т.е если часы после синхронизации отстают на 15мин или на час мы смело спишем это на погрешность в пределах допуска? нет же.

    я вас не агитирую отказываться от лишних запросов (я то их действительно считаю бесполезными, ненужными и только вредными)
    если даже вы решите выполнить сотню запросов, и и на все эти запросы получите абсолютно идентичные ответы, если сто раз их сравните побитно, потом сто раз побайтно, сто раз словами, сто раз со сдвигами, свапя и прочими ухищрениями... сто раз убедитесь в том, что это самая истинная истина из всех истин, глюк, о котором я говорю никуда не исчезнет и в какой-то момент примет совсем другое решение, отличное от Вашего и сделает иначе... на свое усмотрение, наплевав на истину сотни запросов :)

    прикольно, только это проблема как бы в прошлом, и самое главное, как бы наследственная... :D
    о которой сообщают форумчане выше. это же не о моем коде они пишут. вы, случайно, не знакомы с автором этого кода? :)
    а так как я эту проблему решал и устранял, пожелал помочь и косвенно направить по правильному пути а не ложному. дал Вам подсказку и лог.
    в моем редакции Вашего кода, остался один запрос ассинхронный. и так как способов решения несколько, мне было интересно какой выберете Вы
    но Вы видимо мой лог не смотрели и совсем не желаете понять сути проблемы
    проблему, на которую надо "ширше" смотреть... за рамки одной функции. а не только как на элементарную раскладку 4 байт.

    думаю... повторюсь, думаю что Вы глюк не там ищите, там где его нет, или точнее вообще не ищите а упрямо пытаетесь эту проблему "замаскировать"
    глюк рано или поздно даст о себе знать, такие "приколы" месяцами могут не заявлять о себе, а могут проявиться незаметно... ну не было меня дома и часы с собой не взял :) тут глюк он ведь какой... пришел и ушел... может через минуту вернуться а может через месяц.

    Иван, вопрос чисто из любопытства, Вы ассемблер какой либо из платформ изучали?
     
    Последнее редактирование: 20 июл 2023
  3. IvanUA

    IvanUA Гуру

    Да вы правы, во время бегущей строки работает только веб, mqtt и функции по прерываниям. NTP обновление времени в этот период не выполняется.
    Речь идет о 1-2 секундах максимум... Сейчас это 250-2400мс.
    Есть такое выражение. Очень тяжело искать черную кошку в темной комнате, особенно если ее там нет.
    Это я к чему. Легко искать глюк - когда он у вас есть... Если я его не могу поймать у себя на устройствах то как я могу его поправить.
    По этому и прошу если кто ловит глюки описуйте более подробно, что бы я мог как то это исправить.
    У меня лично в использовании находятся пять экземпляров часов и единственный глюк что я поймал - это при старте часав возникала путанница с переходом на летнее и зимнее время. Это решается или часовым модулем или двойным запросом времени при старте.
    Ну я так понимаю что вы нашли и побороли эту болячку?!
    И на сколько я понял из вашего сообщения болячка заключалась в том что в тот момент когда синхронизация времени пыталась обновить переменные времени, в этот момент эти же переменные обновлялись по прерыванию из функции локального счетчика времени?
    Если так, то мне кажется что это лечится запретом прерываний на момент записи полученных значений от NTP сервера.
    И да, я не догадался что означают восклицательные знаки. :(
    Нет. Не изучал целенаправленно. Я больше электронщик чем прогер)))
    Максимум куда я лез в дебри, так это были машинные коды Z80...
     
  4. DiMaro

    DiMaro Нерд

    Иван, не скажу что этот баг очень часто у меня проявлялся.
    И возможно, именно не малое количество имеющихся и у меня часов, сейчас насчитал 7 штук, куда входят не только на MAX, но и семисегментные на ws2818 и на RGB матрицах (пока еще тестовые варианты, плюс еще всякая мелкая хрень, которую не считаю так как время не является основной функцией девайсов), заставили обратить внимание на проблему... это не вопрос одного дня. чем больше девайсов перед глазами тем, соответственно, больше шансов столкнуться с этой проблемой. если бы у меня были только одни часы я бы наверное и не стал замарачиваться, списал бы на что угодно как временную проблему, возможно... не знаю
    да, везде где эти переменные модифицируются. это "классический" метод... это ваш выбор и я его уважаю.
     
    IvanUA нравится это.
  5. IvanUA

    IvanUA Гуру

    немного сменил код
    Код (C++):
      timeLocal.detach(); //забороняємо роботи локального годинника
      while (run_timeLocal) { //якщо локальний годинник ще працює, то чекаємо закінчення
        /* code */
      }
     
      hour = g_hour;
      minute = g_minute;
      second = g_second;
      day = g_day;
      dayOfWeek = g_dayOfWeek;
      month = g_month;
      year = g_year;
      if (rtcAddr > 0) {
        hour_rtc = hour;
        minute_rtc = minute;
        second_rtc = second;
        month_rtc = month;
        day_rtc = day;
        dayOfWeek_rtc = dayOfWeek;
        year_rtc = year;
        setRTCDateTime();
      }
      timeLocal.attach(0.15, timeLocale);
    Если кто будет добавлять то надо в код добавить еще один флажек (run_timeLocal)
    В начале локального обновления его "подымать", в конце "опускать"...
     
  6. DiMaro

    DiMaro Нерд

    Иван, я не понял смысла вот этого...
    Код (C++):
      while (run_timeLocal) { //якщо локальний годинник ще працює, то чекаємо закінчення
        /* code */
      }
    про вебсервер не забыли?
     
  7. DiMaro

    DiMaro Нерд

    флаг не нужен и ожидающий цикл тоже...
    такое условие не достижимо в принципе
    другими словами, флаг и цикл не мешают, но и смысла в них никакого нет...
    потому как...

    1. Вам не удасться отключить прерывание если
    такое возможно, если потребуется, но только в самом прерывании.
    2. Если прерывание выключено, зачем что-то ждать?

    у нас esp8266, одно ядро, а следовательно инструкции с учетом прерываний выполняются квазипараллельно
    можно и флагом разрулить ситуацию но тогда нет смысла отключать прерывание, так будет особенно полезно если в прерывании, которое отчитывает локальное время, выполняется и другие критические функции отключение которых нежелательно. только наоборот, в основе управляем флагом а в прерывании контрим.
    так что можно смело убрать и флаг и цикл и не жалеть их
     
  8. IvanUA

    IvanUA Гуру

    Ну это скорее всего так сказать задел на возможное будующее)))
    Сейчас при одном потоке эта операция ничего не решает. Прерывание останавливает выполнение основного кода до конца выполнения функции в прерывании... Но. Возможно в дальнейшем что код будет перенесен на другую платформу, и там будет два независимых потока, вот тогд нужно понимать что в данный момент работает.... По большому счету этот цикл просто не будет в данном коде выполняться....
    совершенно верно, но я перестраховщик. Вот даже зная что функция прерывания не затратная по времени, я все одно в начале выполнения вырубаю прерывания... мало ли, а вдруг потом что допишу и начнут вызываться прерывания внутри прерываний))))
    Код (C++):
    void timeLocale() {
      run_timeLocal = true;
      timeLocal.detach();
    ...
    ...
    ...
      timeLocal.attach(0.15, timeLocale);
      run_timeLocal = false;
    }
    Точно, забыл, там же можно время менять из веба и приложения.... Поправлю, но это уже с понедельника (пока закончится воздушная тревога, то надо будет уже и домой идти на выходные)....
     
  9. mikhail09p

    mikhail09p Гик

    Сегодня сбилось время на 1 час. С модулем РТС. Прошивка 5.
    Наверное, при старте модуля не нужно считывать время с сервера, если есть РТС...
    И нету погоды уже 2 дня... На веб страничку часов не зайти... Совсем поломались. :)
    Но время после перезагрузки подтянули.
     
    Последнее редактирование: 27 июл 2023
  10. mikhail09p

    mikhail09p Гик

    Только у меня не работает weatherbit.io ?
     
  11. big_alex

    big_alex Гик

    Я установил время синхронизации раз в сутки, если и происходит сбой, то на 24 часа )))
    Уже неделю часы работают нормально
    Синхронизация каждые 5 минут не помогала, часы сначала отставали на 5, потом на 10, на 15 мин и т.д. до перезагрузки
    К сожалению timeLocal.detach(); - attach тоже эффекта не дало (
     
  12. DiMaro

    DiMaro Нерд

    чудес не бывает... все объяснимо если разобраться
    например вот тут, если судить не по самым "свежим" исходникам, обновление локального времени из RTC модуля
    Код (C++):
    void runService(){
    ...
    ...
          hour=hour_rtc;
          minute=minute_rtc;
          second=second_rtc;
          day=day_rtc;
          month=month_rtc;
          year=year_rtc;
    ...
    ...
    }
    тут тоже могут быть сюрпризы
    глобальные переменные времени желательно объявить с таким квалификатором
    Код (C++):
    volatile uint8_t hour = 12, minute = 0, second = 0, month = 1, day = 1, dayOfWeek = 7;
    volatile uint16_t year = 2023;
     
  13. IvanUA

    IvanUA Гуру

    На сколько я понимаю у человека своя модифицированная прошивка... Так что там нужно сидеть и ловить где происходит глюк.
    Скиньте мне в личку ссылку на вашу прошивку, с понедельника в отпуск, но возможно будет время поковырять... Поищу ваш глюк, если он так часто вылазит....

    Собрал себе лайт версию часиков.
    [​IMG]
    Оставил только датчик ДС18, прогноз погоды и будильники...
    На борту часовой модуль, датчик ДС, фоторезистор, пищалка и кнопка.
    Оставил только английский и украинский языки. Все лишнее вычистил.
    Прошивка весит легче метра))))
    Корпус склеили из рекламного пластика и покрасил.
    Размер получился 70х70х22мм
    [​IMG]
    Короткое видео тут
     
    max50a5, mikhail09p и ur5ncb нравится это.
  14. mikhail09p

    mikhail09p Гик

    Уже 2 дня сбивается время на 1 час. После перезагрузки лечится. С модулем РТС. Прошивка 5.
    Это после пропадания электричества.
    А с прошивкой 4 не сбивается...
     
    viktor6 нравится это.
  15. IvanUA

    IvanUA Гуру

    На "кубике" поймал такой же глюк, второе утро встаю, а часы на час отстают....
    Есть шанс поискать природу глюка
     
    Последнее редактирование: 13 авг 2023
    ur5ncb нравится это.
  16. IvanUA

    IvanUA Гуру

    Вы как всегда правы)))
    Хотя я тоже был прав что искать глюк когда он себя не проявляет очень тяжело.
    Короче мне повезло и одни мои часики таки ловили иногда этот глюк (писал выше).
    Основная моя проблема была в паузе между запросом и ответом сервера.
    При очень коротком запросе, когда ответ еще не получен, я давал повторный запрос.
    При этом получал два ответа. Один обрабатывался и мы получали время, а второй зависал в udp-ной функции.
    При повторном запросе через 1 час, мы обрабатывали старый ответ, а новый получаем и храним в памяти....
    Вот таким образом и получался сдвиг времени на время повторного запроса.
    Так что я таки сделал один запрос и паузу в 1 секунду до обработки. Эту секунду я потом учитываю при обработке времени.
    Это кончено не панацея, но очень велика вероятность что таких глюков больше не будет.
    Если же снова начнет вылезать такая лажа, то придется лезть в функцию udp и смотреть как можно чистить её данные в случае неудачного ответа.
    Прошивку обновил на гитхабе. Просьба потестировать и отписаться.
     
    viktor6 нравится это.
  17. DiMaro

    DiMaro Нерд

    легко... у меня так реализованно.
    udp буфер локальный, не глобальный
    Код (C++):

    void sendNTPpacket() {

      statusUpdateNtpTime = false;

    ...
    ...

      uint8_t packetBuffer[NTP_PACKET_SIZE];
      memset(packetBuffer, 0, NTP_PACKET_SIZE);

      udp.parsePacket();
      if (udp.available()) udp.flush();  // если есть непрочитанные данные очищаем буфер UDP

    ...
    ...

      udp.write(packetBuffer, NTP_PACKET_SIZE);
      if (!udp.endPacket()) {
        if (printCom) Serial.println(F("\t Package Send Error"));
        return;
      }

      t1 = millis();                   // запомнили время запроса
      allowWaitingResponseNTP = true;  // ожидаем ответ

    }
     
    алгоритм следующий.
    запрос... и сразу по своим другим неотложным делам
    5 секунд таймаут
    если в течении этого времени получен ответ, обрабатываем (в среднем тратиться 65мс)
    если ответ не получен, через секунду (5 + 1) повторный запрос
    если используется DNS таймаут лучше увеличить до не менее 7 сек
     
    Последнее редактирование: 14 авг 2023
  18. IvanUA

    IvanUA Гуру

    Я тоже перенес буфер из глобальных переменных в локальные.
    Интересное решение, то есть вы еще до отправки запроса пробуете парсить то, что есть в буфере udp.
    Далее проверяете длину _ctx и если она не нулевая делаете
    Код (C++):
    void WiFiUDP::flush()
    {
        endPacket();
    }
    Не пробовали использовать udp.stop(); ?
    Код (C++):
    void WiFiUDP::stop()
    {
        if (_ctx) {
            _ctx->disconnect();
            _ctx->unref();
        }
        _ctx = 0;
    }
    Я так понимаю что если не будет ответа сервера, то есп будет долбить его каждые 6 секунд?

    ПС. Не подскажете как делаете коррекцию задержки? и нужна ли оно вообще?
     
    Последнее редактирование: 14 авг 2023
  19. DiMaro

    DiMaro Нерд

    после stop, ИМХО скорее всего будет требоваться повторная инициализация udp => begin, что на мой взгляд, не очень желательное решение в данном случае
    от 6 до 13...
    ваш код "долбит" или "долбил" сервер трижды по 0.8 секунд и это Вас никак не смущало :)
    а от 6 секунд... целая вечность по меркам микроконтроллера
    можно, если необходимо, сделать ограничение, но на практике, т.к. адрес в пуле динамически сменяется, пока не требовалось... все нормально.
    на матрице RGB во время строки визуально даже не заметна синхронизация
    по мне так, если и не необходима, то желательна, отправлю в лс...
     
  20. IvanUA

    IvanUA Гуру

    Совершенно верно.
    Код (C++):
    int WiFiUDP::beginPacket(IPAddress ip, uint16_t port)
    {
        if (!_ctx) {
            _ctx = new UdpContext;
            _ctx->ref();
        }
        return (_ctx->connect(ip, port)) ? 1 : 0;
    }
    Но я вставил этот костылик до инициализации соединения)))
    Смущало... По этому сейчас делаю только один запрос, если не удалось, то повторно уже через 5 минут)))
    Ну и на всякий случай я сделал такую проверку
    Код (C++):
      if (packetBuffer[32] != packetBuffer[40] || packetBuffer[33] != packetBuffer[41] ||
          packetBuffer[34] != packetBuffer[42] || packetBuffer[35] != packetBuffer[43]) {
        if (senss.printCom) {
          printTime();
          Serial.println("Чаз запита та час відповіді різняться...");
        }
        statusUpdateNtpTime = 0;
        return;
      }
    С учетом того что НТП сервера довольно шустрые, и сколько я не наблюдал то время приема и отправки совпадает.
    Если совсем тугой сервер, то можно не проверять младший байт или пару младших бит...
    А вот если вдруг придет пакет к примеру в котором все ноли, тогда....... Но пока такого не видел...
    Ну и да... при первом запуске, после подключения к WiFi если неудачно было получено время, то вторая попытка будет через 30 секунд. Потом через 5 минут.
    Премного благодарен.
     
    Последнее редактирование: 14 авг 2023