Официальный сайт компании Arduino по адресу arduino.cc
Помогите разобраться с DS3231
- Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии
Вс, 03/03/2019 - 19:34
Помогите разобраться. Почему не выводится в монитор порта, время и дата?(пустая строка, потом строка Sleep, потом строка Wake UP и опять пустая строка. Хотя таймер работает. С ардуинкой только знакомлюсь. Пробовал другой скетч с таймером, таже ерунда, а если залить просто время, то выводится .
#include <DS3231.h> #include <avr/sleep.h> #include <avr/power.h> #define WakePin 2 DS3231 clock; RTCDateTime dt; void rtcUp() { } void(*resetFunc) (void) = 0; void setSleepTimer(int mins) { uint8_t hours = mins / 60; uint8_t mins_left = mins - hours * 60; dt = clock.getDateTime(); uint8_t hnow = dt.hour; uint8_t mnow = dt.minute; uint8_t sec = dt.second; mnow += mins_left; if (mnow >= 60) { mnow -= 60; hnow += 1; } hnow += hours; if (hnow > 23) { hnow -= 24; } clock.setAlarm1(0, hnow, mnow, sec, DS3231_MATCH_H_M_S); } void sleepNow() { ADCSRA = 0; power_all_disable(); set_sleep_mode(SLEEP_MODE_PWR_DOWN); attachInterrupt(0, rtcUp, LOW); sleep_enable(); sleep_mode(); sleep_disable(); power_all_enable(); detachInterrupt(0); } void setup() { pinMode(WakePin, INPUT_PULLUP); Serial.begin(9600); clock.begin(); clock.enableOutput(false); clock.armAlarm1(false); clock.armAlarm2(false); clock.clearAlarm1(); clock.clearAlarm2(); } void loop() { dt = clock.getDateTime(); Serial.println(clock.dateFormat("d-m-Y H:i:s - l", dt)); setSleepTimer(1); Serial.println("Sleep"); delay(100); sleepNow(); Serial.println("Wake UP"); //resetFunc(); }
Вы сами-то можете что-то прочитать на этой картинке?
Скетч я выложил ниже, что бы его можно было прочитать. А на картинке изображение с монитора порта. На ктоторой видно пропуски времени и даты.
с монитора порта. На ктоторой видно пропуски времени и даты.
И Вы можете прочитать, что там написано? ну, тогда читайте и решайте свою проблему сами.
Когда узнаете о существовании операций Copy и Paste - возвращайтесь.
— Ну скажи что-нибудь, ты же у нас самый сообразительный.
— Я могу сказать только, что один из них Женя.
"Ирония судьбы, или С легким паром!"
ямогу сказать только одно
возвращает пустую строку :)
ямогу сказать только одно
возвращает пустую строку :)
А что не так в этой строке? Задается формат вывода даты и время.
ссылку на библиотеку DS3231 дайте.
ссылку на библиотеку DS3231 дайте.
https://github.com/jarzebski/Arduino-DS3231
Не совсем понятно, для чего автор библиотеки возвращает результат выполнения dateFormat указывающий на на буфер, который выделялся в стеке.
Опасный код, если передавать результат в другую функцию, у которой на старте будут инициализированы переменные в стеке, то обратившись к полученному результату из dateFormat можно попасть неизвестно куда.
автор библиотеки возвращает результат выполнения dateFormat указывающий на на буфер, который выделялся в стеке.
Хрена се!
Хрена се!
А не могли бы вы пояснить будет ли работать такой код? Работать то он работает, hello arduino выводит, но по сути выходя из функции foo() переменная buffer вроде как не должна существовать? Но скорее я что то с указателями не понял.
Хрена се!
А не могли бы вы пояснить будет ли работать такой код? Работать то он работает, hello arduino выводит, но по сути выходя из функции foo() переменная buffer вроде как не должна существовать? Но скорее я что то с указателями не понял.
Хрена се!
А не могли бы вы пояснить будет ли работать такой код?
Я дополню коллегу из поста #11.
В принципе, даже, если бы она не была inline, в таком виде это всё равно бы работало.
Переменная «не должна существовать» в том смысле, что память, выделенная под неё, при выходе из функции объявляется свободной и её может занять кто угодно. А возвращённый указатель по-прежнему на неё указывает.
Но в Вашем примере, никто не успел эту память загадить и потому в ней остаётся тоже, что туда прописала функция, и всё выглядит нормально. Вот если бы Вы между вызовом функции и печатью, вставили что-нибудь, что тоже хватает свободную память из стека и туда пишет, вот тогда бы она у Вас не сработала, т.к. память была бы уже загажена.
Т.е. такое использование памяти ведёт не к немедленному краху, а к появлению труднообъяснимых фантомных глюков, которые появляются и исчезают трудно объяснимым образом, при внесении каких-то совершенно безобидных изменений в программу.
ЕвгенийП - а можно еще чуть уточнить ?
То, что подобное использование буфера есть говнокод - для меня совершенно очевидно. Но что изменится, если мы выделим под возвращаемое значение обьект типа String? - для меня и это выглядит неправильным, однако помню дискуссиию, где вроде бы именно Вы обьясняли, что с обьектами так делать можно. Не могли бы Вы пояснить?
Если плохо сформулировал - не отвечайте, так и скажите. Тогда либо постараюсь спросить правильнее, либо оставим вопрос на потом
Я дополню коллегу из поста #11.
Т.е. такое использование памяти ведёт не к немедленному краху, а к появлению труднообъяснимых фантомных глюков, которые появляются и исчезают трудно объяснимым образом, при внесении каких-то совершенно безобидных изменений в программу.
Благодарю за разъянения. Все таки лыжи не едут, а я понял правильно :-) Данные будут существовать пока не затруться.
Я обычно в таких случаях объявляю буфер, передаю в функцию ссылку на буфер, в функции буфер заполняю и потом использую по надобности.
Со стрингом всё будет точно так же - если в него копировать сразу, то всё будет ОК. А ежели посреди копирования какая-нить функция из прерывания будет нуждаться выделении памяти и похерит \0 в возвращаемом буфере, то получится зависание. Или ребут. Или как повезёт.
Системные функции сделаны иначе:
Таким образом, если память и будет подпорчена, то явно пользователем(погроммистом).
Со стрингом всё будет точно так же - если в него копировать сразу, то всё будет ОК.
Системные функции сделаны иначе:
Не, Гриш, как правильно обращаться с буфером - я знаю. Я спрашивал вот про такой вариант:
я правильно понимаю, что у ТС конструкция
с данной библиотекой, сработае правильно в 99% случаев ?
я правильно понимаю, что у ТС конструкция
с данной библиотекой, сработае правильно в 99% случаев ?
если не учитывать случаи нехватки памяти (нафига там выделяется 255 символов?????) - то скорее да, чем нет
Не, Гриш, как правильно обращаться с буфером - я знаю. Я спрашивал вот про такой вариант:
Тут я не копенгаген, стрингами не пользуюсь, в классы не лезу без необходимости.
Тут я не копенгаген, стрингами не пользуюсь, в классы не лезу без необходимости.
у меня точно так же :)
Начал тебе писать... и вроде бы сам нашел ответ на свой вопрос.
С классами так работать можно, если внутри класса нет ссылочных переменных. При возврате класса из функции в этом месте основной программы создается новый экземпляр, в который копируется возвращаемое значение.После этого экземпляр, созданный внутри функции - уничтожается и с памятью все нормально.
Пусть опытные поправят, если где неверно написал
Кто то может мне дать ответ, что я делаю не так. Почему команда
Serial
.println(clock.dateFormat(
"d-m-Y H:i:s - l"
, dt)), в монитор порта выводит пустую строку. Но при этом таймер работает исправно.
Кто то может мне дать ответ, что я делаю не так. Почему команда
Serial
.println(clock.dateFormat(
"d-m-Y H:i:s - l"
, dt)), в монитор порта выводит пустую строку. Но при этом таймер работает исправно.
когда компилируете полный код - там пишется сколько он занимает во флеше и ОЗУ. Какие там цифры?
Если возвращать сам объект, а не ссылку, то можно (но тоже - говнокод). Но здесь мы касаемся очень тонких вещей!
Что действительно произойдёт при возврате из функции, на самом деле зависит от миллиона причин. От наличия или отстутствия конструкторов копирования и конструкторов перемещения, от того, по какому стандарту сделан компилятор, т.к. это т.н. "семантика перемещения" ("move semantics") - она сейчас развивается и стандарты 11-го, 14-го и 17-го годов сильно различаются в этой части.
В каком-то случае при возврате из фунции, будет создан новый объект и именно он будет возвращён. В другом случае (если есть конструктор копирования или перемещения) локальный объект может быть скопироваи/перемещён в возвращаемый. Там много очень тонких вещей. Вы на самом деле коснулись материи, которая сейчас активно развивается и меняется.
На самой заре ООП в этом случае требовалось создавать новый объект. Но это большие расходы. Появилась идея "конструкторов копирования", но это тоже решает не все проблемы. Особенно трудно, когда конструкторы и деструкторы имеют побочные эффекты. Тогда появилась "семантика перемещения" и понятие prvalue (наряду с rvalue и lvalue), но и тут много граблей, т.к., например, вызывающий код и вызываемая функция могут находиться в разных ядрах, или, того хлеще, в разных узлах кластера - там проблемы растут комом.
Здесь (в классе String) всё реализовано через копирование, но заметьте, от каких неуловимых нюансов зависит, что же реально будет происходить. Сравните два кода ниже:
Вся разница в том, что строки №№ 10 и 11 левого скетча объедины в одну - строка №10 правого. Никакой другой разницы нет.
А теперь давайте посмотрим на трассировку вызовов конструкторов, деструкторов и запросов/освобождения памяти (листинги под кодами).
Слева мы видим, что res в функции setup и s в функции convert - это два разных объекта с адресами 2294 И 2288 соответственно. В момент возврата из функции, буфер объекта res (addr 592) был освобождён, а буфер объекта s (addr 596) не освобождался (!!!) а просто был переназначен объекту res. Т.е. получается, что (нумерация строк по левому листингу)
1. В строке 3 запрошена память для объекта res
2. В строке 5 запрошена память для объекта s
3. В строке 7 освобождена память объекта res
4. Буфер объекта s переназначен объекту res (это копирование)
5. В строке 11 освобождена память объекта res
Т.е. получается, что у нас два объекта, мы под оба запрашивали буферы, но освобождали только у одного объекта, зато дважды. А буфер второго объекта по ходу дела перекочевал к первому.
А вот в правом примере, изменения в коде казалось бы плёвые, но что имеем внутри!!! Здесь у нас s и res - это просто один и тот же объект с адресом 2294. А казалось бы, ничего толком и не менялось в коде-то.
В общем, в конечном итоге оно сработает нормально. Но что будет внутри - это очень сложные вещи, которые, к тому же, прямо на наших глазах меняются. Современное состояние вопроса (стандарт 17-го года) можно почитать в статьях, посвящённым семантике перемещения и prvalue.
Кто то может мне дать ответ, что я делаю не так. Почему команда
Serial
.println(clock.dateFormat(
"d-m-Y H:i:s - l"
, dt)), в монитор порта выводит пустую строку. Но при этом таймер работает исправно.
А попробуйте пример из вашей библиотеки который называется DS3231_dateformat.ino залить в ардуино и посмотреть что выводит.
И, да, b707, если Вы подумаете. что в правом примере из #24 получился один объект из-за inline, то нет. Можно вынести функцию в другой файл, вызвать как extern - результат тот же. Ничего не изменится.
Евгений. спасибо огромное!
Кто то может мне дать ответ, что я делаю не так. Почему команда
Serial
.println(clock.dateFormat(
"d-m-Y H:i:s - l"
, dt)), в монитор порта выводит пустую строку. Но при этом таймер работает исправно.
когда компилируете полный код - там пишется сколько он занимает во флеше и ОЗУ. Какие там цифры?
Кто то может мне дать ответ, что я делаю не так. Почему команда
Serial
.println(clock.dateFormat(
"d-m-Y H:i:s - l"
, dt)), в монитор порта выводит пустую строку. Но при этом таймер работает исправно.
А попробуйте пример из вашей библиотеки который называется DS3231_dateformat.ino залить в ардуино и посмотреть что выводит.
Одиссей - вы плохо соображаете или плохо запоминаете? Вам уже в начале обсуждения сказали, что на Ваших скринах ничего не видно! -Не надо эту фигню постить - выкладывайте вывод программы как текст, уважайте других участников!
Если кратко, DS3231 у вас не работает.
Если кратко, DS3231 у вас не работает.
а это не библиотека кривая? - по-моему. вместо форматированной даты она справку по формату выдает
нее, часы "заводятся" и выводится та-же dt (RTCDateTime).
Если кратко, DS3231 у вас не работает.
Почему тогда это скетч работает?
Почему вы всех мучаете, требуя рассказать, почему велосипед с квадратными колёсами не едет, а с круглыми едет? Попробуйте сами разобраться - это же ваше хобби. Накидайте отладочных выводов в библиотеку и локализуйте проблему.
потому что тут
а там
ну если разжевать - используются разные библиотеки DS3231.
Небыло под рукой модуля ds3231 поэтому в примере выкинул его инициализацию, только задал статический RTCDateTime
По хорошему не хочет работать, вывод:
А под давлением? в DS3231::dateFormat сделал буфер статическим
Так то лучше, вывод:
Не очень хороший тон, возвращать указатели которые смотрят на стек.
Спасибо помогло, но при компиляции есть предупреждения типа
warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
return "Unknown";
Как это можно исправить?
Например, явно преобразовать константы к char *
Дык там тот же треш с возвратом указателя смотрящего на стек.
Мало того, что автор библиотеки не объявил возвращаемый указатель как константный, так и у нестатического метода, который не меняет значения класса, не добавил декларацию const для метода.
Дык там тот же треш с возвратом указателя смотрящего на стек.
Явно описанные константы вроде ("Monday") - не стек, с ними всё в порядке.
автор библиотеки не объявил возвращаемый указатель как константный
Нет смысла возвращать константый указатель (всё равно компилятор проигнорирует). Здесь нужно возвращать указатель на константу (т.е. сам по себе указатель не костантный, но он указывает на костантное содержимое). Вот сравните три записи. И, кстати, попробуйте скомпилировать и посмотрите на какие строки будут предупреждения (и какие), а на какие - нет.
у нестатического метода, который не меняет значения класса, не добавил декларацию const для метода.
Это да.