Часы DS3231 не работает нормально скетч из примера
- Войдите на сайт для отправки комментариев
Доброго времени. Прошу помощи в понимании проблемы / кода.
Делаю метеостанцию на 128 меге. Решил добавить функцию будильника, т.к. жалко использовать память чипа только на 30% (в ардуину чуть не влезает). Решил использовать аппаратный будильник DS3231. Пришлось использовать другую библиотеку, т.к. в той, что использовал не было функций управления будильником.
Появилась проблема - не работает функция перевода даты, времени в текст.
Вот сам скетч из примера:
/* DS3231: Real-Time Clock. Date Format Read more: www.jarzebski.pl/arduino/komponenty/zegar-czasu-rzeczywistego-rtc-ds3231... GIT: https://github.com/jarzebski/Arduino-DS3231 Web: http://www.jarzebski.pl (c) 2014 by Korneliusz Jarzebski */ #include <Wire.h> #include <DS3231.h> DS3231 clock; RTCDateTime dt; void setup() { Serial.begin(9600); // Initialize DS3231 Serial.println("Initialize DS3231");; clock.begin(); // Set sketch compiling time clock.setDateTime(__DATE__, __TIME__); // Set from UNIX timestamp // clock.setDateTime(1397408400); // Manual (YYYY, MM, DD, HH, II, SS // clock.setDateTime(2014, 4, 13, 19, 21, 00); } void loop() { dt = clock.getDateTime(); Serial.print("Long number format: "); Serial.println(clock.dateFormat("d-m-Y H:i:s", dt)); Serial.print("Long format with month name: "); Serial.println(clock.dateFormat("d F Y H:i:s", dt)); Serial.print("Short format witch 12h mode: "); Serial.println(clock.dateFormat("jS M y, h:ia", dt)); Serial.print("Today is: "); Serial.print(clock.dateFormat("l, z", dt)); Serial.println(" days of the year."); Serial.print("Actual month has: "); Serial.print(clock.dateFormat("t", dt)); Serial.println(" days."); Serial.print("Unixtime: "); Serial.println(clock.dateFormat("U", dt)); Serial.println(); delay(1000); }
Т.е. Serial.println(clock.dateFormat... - ничего не выводит.
Вот сама функция из библиотеки:
char const* DS3231::dateFormat(const char* dateFormat, RTCDateTime dt) { char *buffer[255]; buffer[0] = 0; char helper[11]; while (*dateFormat != '\0') { switch (dateFormat[0]) { // Day decoder case 'd': sprintf(helper, "%02d", dt.day); strcat(*buffer, (const char *)helper); break; case 'j': sprintf(helper, "%d", dt.day); strcat(*buffer, (const char *)helper); break; case 'l': strcat(*buffer, (const char *)strDayOfWeek(dt.dayOfWeek)); break; case 'D': strncat(*buffer, strDayOfWeek(dt.dayOfWeek), 3); break; case 'N': sprintf(helper, "%d", dt.dayOfWeek); strcat(*buffer, (const char *)helper); break; case 'w': sprintf(helper, "%d", (dt.dayOfWeek + 7) % 7); strcat(*buffer, (const char *)helper); break; case 'z': sprintf(helper, "%d", dayInYear(dt.year, dt.month, dt.day)); strcat(*buffer, (const char *)helper); break; case 'S': strcat(*buffer, (const char *)strDaySufix(dt.day)); break; // Month decoder case 'm': sprintf(helper, "%02d", dt.month); strcat(*buffer, (const char *)helper); break; case 'n': sprintf(helper, "%d", dt.month); strcat(*buffer, (const char *)helper); break; case 'F': strcat(*buffer, (const char *)strMonth(dt.month)); break; case 'M': strncat(*buffer, (const char *)strMonth(dt.month), 3); break; case 't': sprintf(helper, "%d", daysInMonth(dt.year, dt.month)); strcat(*buffer, (const char *)helper); break; // Year decoder case 'Y': sprintf(helper, "%d", dt.year); strcat(*buffer, (const char *)helper); break; case 'y': sprintf(helper, "%02d", dt.year-2000); strcat(*buffer, (const char *)helper); break; case 'L': sprintf(helper, "%d", isLeapYear(dt.year)); strcat(*buffer, (const char *)helper); break; // Hour decoder case 'H': sprintf(helper, "%02d", dt.hour); strcat(*buffer, (const char *)helper); break; case 'G': sprintf(helper, "%d", dt.hour); strcat(*buffer, (const char *)helper); break; case 'h': sprintf(helper, "%02d", hour12(dt.hour)); strcat(*buffer, (const char *)helper); break; case 'g': sprintf(helper, "%d", hour12(dt.hour)); strcat(*buffer, (const char *)helper); break; case 'A': strcat(*buffer, (const char *)strAmPm(dt.hour, true)); break; case 'a': strcat(*buffer, (const char *)strAmPm(dt.hour, false)); break; // Minute decoder case 'i': sprintf(helper, "%02d", dt.minute); strcat(*buffer, (const char *)helper); break; // Second decoder case 's': sprintf(helper, "%02d", dt.second); strcat(*buffer, (const char *)helper); break; // Misc decoder case 'U': sprintf(helper, "%lu", dt.unixtime); strcat(*buffer, (const char *)helper); break; default: strncat(*buffer, dateFormat, 1); break; } dateFormat++; } return *buffer; }
По ней хотел спросить, как понимать switch (dateFormat[0])? Именно dateFormat[0].
Вот ссылка на библиотеку: https://github.com/jarzebski/Arduino-DS3231
Вот так у меня выглядит:
Возвращать из функции указатель на char[] - плохая идея.
Библиотеку рефакторить необходимо.
А если 27ю строку раскоментировать?
Функция возвращает указатель на ЛОКАЛЬНЫЙ объект, такое иногда работает, но как повезёт.
Сами часы работают, не работает преобразование числового формата в строку. Если выводить цифрами, то все ок.
не работает преобразование числового формата в строку. Если выводить цифрами, то все ок.
Так я же Вам написал в #3, что оно и должно через пень колоду работать и сказал в чём именно ошибка. Вы не поняли того поста?
Это, я понял, но не успел отредактировать сообщение. Хотел попросить пнуть в нужную сторону, т.к. я не программист и эти подробности для меня пока темный лес. Решение, я конечно найду со временем. Но хотелось бы сделать правильно.
Прочитай документацию на sprintf и напиши сам. А этот кошмар забудь.
темный лес ... Решение, я конечно найду со временем.
Вам полезнее было бы разобраться с темнотой и решить проблему самостоятельно.
Но если хотите по-мартышечьи, то для начала попробуйте убедиться, что проблема о которой я написал единственная. Устраните её и попробуйте. Для устранения в функции DS3231::dateFormat замените строку №3 (по Вашей вставке) на
в везде (от слова ВЕЗДЕ) в этой функции замените "*buffer" на "buffer". Попробуйте, что из этого выйдет.
Если не заработает, не забудьте выложить свежий текст функции.
P.S. Я не считаю правильным выполнять такую операцию библиотечной функцией (за исключением случая, когда хочется чего-то совсем экзотического). Со стандартными преобразованиями вполне справляются штатные системные средства без всяких сторонних библиотек.
Прочитай документацию на sprintf
Зачем, когда вполне доступна strftime?
Затем, что библиотека не возвращает struct tm. Затем, что начинать надо всё равно со sprintf.
Затем, что библиотека не возвращает struct tm. Затем, что начинать надо всё равно со sprintf.
С какого бодуна? Кто или что мешает struct tm создать? И зачем для этого sprintf?
ЕвгенийП, это я сделаю, но и попробую разобраться, как сделать правильно. Можно, еще вопрос, как понимать: switch (dateFormat[0]) - что значит dateFormat[0], это же вроде указатель на константу типа char. В данном случае, я бы написал switch(*dateFormat), т.е. переключаемся в зависимости от значения по указателю. Нет?
МЛЯ, ЭТО ТРОЛЛИНГ????
Посмотрел библиотеку ПО ВАШЕЙ ССЫЛКЕ! Там функция dateFormat тоже с ошибками, но не такая, как та, что Вы выложили!!! Вот её начало, сравните с тем, что у Вас в стартовом посте.
Зачем Вы пудрите нам мозг фейковым текстом? Заняться больше нечем?
dateFormat[0] - я бы написал *dateFormat
Это одно и то же. Пофиг, как писать.
Вы, сначала, ответьте на мой пост #13, а то я близок к тому, чтобы послать Вас нах.
Ах да. Еще strftime в avr не умеет в локали.
Ах да. Еще strftime в avr не умеет в локали.
А, ну тогда понятно.
Заработало! Хотя в первом посту функция была из старой версии библиотеки, которую компилировал уже не было * у buffer. Добавление static помогло. Можно еще вопрос или так сказать правильно ли я понимаю суть проблемы? Функция в данном случае возвращает указатель на локальную для ф-ции переменную/данные, которая уничтожается/перезаписывается при выходе из этой функции. Соответственно указатель может быть верным, если МК данные не перезаписал/стер или ссылаться не понятно на какие данные. Добавив static, массив buffer сохраняет значение между вызовами функции. По-этому функция возвращает указатель правильные на данные? Т.е. можно было просто вынести переменную вне функции?
Т.е. можно было просто вынести переменную вне функции?
Да. Но вся функция написана кошмарным рукожопом и этого мало.
А мне вот интересно, КТО сочиняет все эти рукожопые библиотеки? И как бы их фильтровать по степени рукожопости? Ведь, иной раз, просто диву даёшься их кривости! Так может нужно создать какой то комитет, по аналогии с Мизулиной(?
может нужно создать какой то комитет, по аналогии с Мизулиной(?
Для начала надо найти того, кто будет платить комитетчикам так, как платят Мизулиной. А без этого в комитете, боюсь, никого не окажется :-(
Функция в данном случае возвращает указатель на локальную для ф-ции переменную/данные, которая уничтожается/перезаписывается при выходе из этой функции. Соответственно указатель может быть верным, если МК данные не перезаписал/стер или ссылаться не понятно на какие данные. Добавив static, массив buffer сохраняет значение между вызовами функции. По-этому функция возвращает указатель правильные на данные? Т.е. можно было просто вынести переменную вне функции?
Указатель верный всегда. А вот областью памяти, на который указывает данный верный указатель, компилятор волен распоряжаться как угодно после выхода из функции - писать туда новые данные, очищать и пр. Static говорит компилятору - не трожь 255 байт. Поэтому в них ничего не изменяется. Но при этом система не может их использовать более разумно.
Классический подход - передать указатель на зарезервированную область памяти извне в функцию. Так, например, реализовано в https://www.cplusplus.com/reference/cstring/strcpy/ - функции передается указатель на destination и он же возвращается как результат действия (просто для удобства дальнейшего использования).
Для начала надо найти того, кто будет платить комитетчикам так, как платят Мизулиной. А без этого в комитете, боюсь, никого не окажется :-(
Это да. Об этом нужно думать глубже.(
Я понял, что код не ахти (думаю, что пишу не лучше - но я учусь). С вашей помощью он хотя бы заработал.
Убрал варнинги, которые были. Остался 1, не пойму, что не нравиться компилятору:
warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
if (days < 365 + leap)
~~~~~^~~~~~~~~~~~
Вроде все переменные unsigned. Или он считает, что days -= 365 + leap; может меньше 0 быть?
warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
if (days < 365 + leap)
~~~~~^~~~~~~~~~~~
Вроде все переменные unsigned. Или он считает, что days -= 365 + leap; может меньше 0 быть?
Возможно, что одна переменная 16бит, а вторая 8.
"Выкинул" вообще эту функцию из библиотеки, все-равно точно использовать не буду.
Возник еще вопрос... Что не нравиться
в 4ой строке "Short forman witch..." должно быть Ноя, а выводит это...
Из-за чего может быть? Кириллица не нравится?
Вроде все переменные unsigned.
Не все.
По посту #13 пояснения будут?
По #13 посту пояснил в 14м. Просто пока создавал тему, обновил библиотеку... Все заработало.
Там все переменные uint8...16...32.
Если только компилятор думает, что при вычитании может быть отрицательное значение.
Скачал. Когда начал устанавливать библиотеку, ide написал, что она уже есть. Поправил свой скетч под эту библиотеку. В библиотеке поправил вывод на кириллицу (название месяцев, дней недели). Перестала отображаться дата. Создал тему здесь, скопировал функцию из библиотеки. Пока сочинял сообщение, решил, что может быть из-за кириллицы. Чтобы не править текст взад в файле срр, заменил сами файлы из архива. Проверил опять не работает. Создал сообщение. А там уже вот что... Написал как есть.
Про 11 строку, потому и спросил, что там тип days беззнаковое целое. Также в условии, объясните, если не трудно, почему там int, если все переменные в условии uint.
На компилятор я "бочку не качу", просто предположил, не имел желания утверждать.
Потому что при вычислении значения расширяются до int, если влезают в таковую размерность.
Хотя, конечно, uint16 поширше int16... Тут я затрудняюсь. ЕвгенийП, наверное эту специфику прояснит.
365 надо заменить на 365U ?
В общем никогда так не делайте. Если выкладываете текст библиотеки - так и пишите, а если "после своих правок", тоже так и пишите. Бесите немерянно, потому что теряешь время только потому, что тебя кто-то дезинформировал.
А константы?
365 - какого типа? Получается, что правая часть сравнения - знаковая (я уже писал Вам об этом, кстати) Сделайте его беззнаковым 365u и будет Вам счастье.
ЕвгенийП, честно говоря, сам тупанул в 1м посте, я даже и не заметил, что там какие-то изменения были. По поводу типов понял, запомнил. Спасибо за помощь! Буду дальше ковырять...