Как сделать будильник из массива строк
- Войдите на сайт для отправки комментариев
Добрый день. Пытаюсь сделать проект, состоящий из ардуины и модуля реального времени.
Нужно чтобы каждый день срабатывало около 5 будильников в течении года.(всего 1500-2000 будильников)
Время срабатывания будильников пытаюсь записать в строковый "массив", в котором указаны даты и времена этих будильников. Вот код:
void setup(){
Serial.begin(9600);
//сюда я вбил 6 времён будильников
char* myStrings[]={"14.11.2016-10:00", "14.11.2016-11:00", "14.11.2016-12:00",
"14.11.2016-13:00", "14.11.2016-15:00","14.11.2016-20:00"};
int i;
for(i=0;i<=6;i=i+1){
//здесь x - данные,полученные с модуля реального времени ds3231. Если текущее время полученное с модуля реального времени равно времени будильника, то...
if(myStrings[i]==x){
Serial.println("сработало");
}
}
}
void loop(){
}
Проблема в том , что я попробовал записать 500 будильников вместо шести и получил ошибку:
"Недостаточно памяти. Скетч использует 11 454 байт (35%) памяти устройства. Всего доступно 32 256 байт.
Глобальные переменные используют 10 096 байт (492%) динамической памяти, оставляя -8 048 байт для локальных переменных. Максимум: 2 048 байт."
Использую ардуино uno в котором 32кб памяти. Я думаю что нужно каким-то другим образом записать будильники, то есть не в строковый массив а как-то по другому...
кстати 1500 будильников весят 22 кб, если поместить их в обычный блокнот, то есть надежда у меня есть:)
Подскажите как написать код, чтобы он уместился в 32кб памяти моей ардуины? и ещё я боюсь- а хватит ли мощности процессора найти в массиве из 1500 будильников нужный будильник
подключай флешку и читай будильники из текстового файла
так ведь памяти хватает. просто массив помещается толи в динамическую память то ли ещё куда-то куда не стОит его помещать, если я правильно понимаю
Каждый день разное время?
я бы рекомендовал добавить расписание на день и составить годовой план по таким расписаниям. Так делается в школьных звонках и не только.
Каждый день разное время надо, то есть 1500 разных будильников. Кто-то разбирается, как сделать чтобы массив ушёл не в динамическую память которой дано всего 2Кб в ардуине, а во флеш, которая 32Кб?
Если нужно оперативно (то есть без перепрошивки скетча) менять параметры будильников - совет выше был, подключите microSD-card с текстовым файлом(файлами) и читайте параметры из них.
Если не нужно - пользуйтесь PROGMEM, тогда прямо в тексте скетча будет что-то типа const char alarms_list[] PROGMEM = "14.11.2016-10:00,14.11.2016-11:00,14.11.2016-12:00,14.11.2016-13:00,14.11.2016-15:00,14.11.2016-20:00"; Возможности изменить эти данные в процессе работы скетча - не будет.
Лучше так:
Каждый день разное время надо, то есть 1500 разных будильников. Кто-то разбирается, как сделать чтобы массив ушёл не в динамическую память которой дано всего 2Кб в ардуине, а во флеш, которая 32Кб?
PROGMEM вам поможет
А, точно, есть ведь ещё вариант - F().
Лучше так:
не лучше - скорость работы кода будет уменьшаться с течением времени
не лучше - скорость работы кода будет уменьшаться с течением времени
Из-за проверки 1500 условий? Не думаю, что там нужна наносекундная точность... А так да, маленько повлияет.
Каждый день разное время надо, то есть 1500 разных будильников. Кто-то разбирается, как сделать чтобы массив ушёл не в динамическую память которой дано всего 2Кб в ардуине, а во флеш, которая 32Кб?
PROGMEM вам поможет
Совет неверный, т.к. gcc не может расположить такой массив во флеш. Указатели да, строки - нет. Попробуйте это скомпилировать.
Согласен, при таком варианте надо все одной большой строкой.
Лучше так:
не лучше - скорость работы кода будет уменьшаться с течением времени
Тоже не верно, т.к. используется ключевое слово inline и код всегда один и тот же для любого индекса:
если на год, то нафига эту инфу .2016- писать куда-то вообще?
ardoinshik, вы объясните что вам нужно "будить", может есть варианты математически рассчитать..
Тоже не верно, т.к. используется ключевое слово inline и код всегда один и тот же для любого индекса:
Тоже не верно, т.к. используется ключевое слово inline и код всегда один и тот же для любого индекса:
Тоже согласен (на inline внимания не обратил). Но... Исходная дата (в первом сообщении) занимает 16 символов (байт). По условию будет 1500 дат. Т.е. под хранение дат уйдет 24000 байт. Если к каждой дате обратиться более одного раза, то либо inline будет проигнорирован компилятором, либо памяти не хватит. Но это так уже "фантазии".
Этого кода в результирующем файле не будет (на картинке я это показал, там 4 асм команды и call Serial.println() для каждой строки, где идёт обращение к Date[n]). 0x0820 - это вызов метода println().
На этапе компиляции любое обращение к объекту Dates через оператор индексирования развернётся в готовый указатель на область flash, где содержится строка. Ключевое слово inline означает включить тело функции operator[] в место вызова, а оптимизация сократит код функции до значения указателя, которое известно на момент компиляции. Поэтому не важно к какой строке мы обращаемся.
П.С. Т.е. я не совсем правльно пояснил, сам inline не сократит код, это сделает оптимизатор. inline лишь уберёт лишний вызов.
Ааа. Т.е. данные не раскопируются при каждом вызове. Тогда вопрос снят.
Этого кода в результирующем файле не будет (на картинке я это показал, там 4 асм команды и call Serial.println() для каждой строки, где идёт обращение к Date[n]). 0x0820 - это вызов метода println().
На этапе компиляции любое обращение к объекту Dates через оператор индексирования развернётся в готовый указатель на область flash, где содержится строка. Ключевое слово inline означает включить тело функции operator[] в место вызова, а оптимизация сократит код функции до значения указателя, которое известно на момент компиляции. Поэтому не важно к какой строке мы обращаемся.
П.С. Т.е. я не совсем правльно пояснил, сам inline не сократит код, это сделает оптимизатор. inline лишь уберёт лишний вызов.
это как бы хорошо, НО! это же какое-то безобразие - я пишу код и желаю, что бы исполнялся switch, а не происходило обращение к индексу.
inline не везде уместно использовать. Я скопировал этот код из другого моего проекта. Если реализация метода operator[] очень маленькая и меньше, чем код вызова этого оператора, то можно сэкономить, используя inline. Тут нужно смотреть листинги ассемблера для случая с inline и без него, чтобы точно узнать нужен ли он, либо собрать в двух случаях и посмотреть на результаты компиляции.
Этого кода в результирующем файле не будет (на картинке я это показал, там 4 асм команды и call Serial.println() для каждой строки, где идёт обращение к Date[n]). 0x0820 - это вызов метода println().
На этапе компиляции любое обращение к объекту Dates через оператор индексирования развернётся в готовый указатель на область flash, где содержится строка. Ключевое слово inline означает включить тело функции operator[] в место вызова, а оптимизация сократит код функции до значения указателя, которое известно на момент компиляции. Поэтому не важно к какой строке мы обращаемся.
П.С. Т.е. я не совсем правльно пояснил, сам inline не сократит код, это сделает оптимизатор. inline лишь уберёт лишний вызов.
это как бы хорошо, НО! это же какое-то безобразие - я пишу код и желаю, что бы исполнялся switch, а не происходило обращение к индексу.
Никто не запрещает убрать inline и понизить уровень оптимизации. По крайней мере у себя я могу это сделать, но в стандартной среде Arduino вроде бы нельзя управлять уровнем оптимизации (точно не знаю). Я не помню какой ключ испльзуется при -O{n} при сборке.
Вы можете управлять содержимым прошивки, нужно только знать где и что нужно "подкрутить".
Отключить оптимизацию для функции можно, используя __attribute__((optimize("O0"))) в месте её объявления. Попробовал, switch появился.
Отключить оптимизацию для функции можно, используя __attribute__((optimize("O0"))) в месте её объявления. Попробовал, switch появился.
спасибо - теперь я спокоен.
Ещё один вариант изменения уровня оптимизации участка кода.
Не забываем ещё заменить uint8_t у index на uint16_t. То же для Count.
Товарищ Araris посоветовал такой код
но комманда Serial.println(alarms_list[0]); выдает мне "1", или например комманда Serial.println(alarms_list[1]); выдает "4",
т.е все даты стали одним элементом, а мне нужно чтобы каждая дата была отдельным элементом, который в будущем можно будет найти чтобы сверить данные часов реального времени с данными из массива
(с++ - только начал осваивать)
а товарищ uni посоветовал код
он вообще не компилируется, пишет ошибку
too many initializers for 'const char []'
Что ж делать то?
Товарищ uni посоветовал совсем другой код, более удобный и правильный. А по поводу этого кода пару постами ниже есть поправка, что массив строк нельзя так делать. Либо все одной строкой, либо... лучше скопируйте, что посоветовл uni
товарищ uni советовал это объявить как указатели. после char звездочку внидюрь.
Лучше так:
Если вы про этот код, то он тоже не работает, т.к. пишет ошибку
warning: case label value exceeds maximum value for type
Если я правильно понял, то case - случаев не может быть бесконечно, примерно на 256 случае валится эта ошибка
ну так тип переменной поменяйте на uint16_t
Товарищ Araris посоветовал такой код
но комманда Serial.println(alarms_list[0]); выдает мне "1", или например комманда Serial.println(alarms_list[1]); выдает "4",
т.е все даты стали одним элементом, а мне нужно чтобы каждая дата была отдельным элементом, который в будущем можно будет найти чтобы сверить данные часов реального времени с данными из массива
(с++ - только начал осваивать)
Ну тогда имеете отличный повод освоить парсинг строк в С++ )))
тема, нафига писать во флеш .2016- не раскрыта
А меня чертовски интригует фраза "Каждый день разное время надо, то есть 1500 разных будильников." ardoinshik, откройтесь же, каково предназначение устройства ?
А меня чертовски интригует фраза "Каждый день разное время надо, то есть 1500 разных будильников." ardoinshik, откройтесь же, каково предназначение устройства ?
очевидно же - профессор сидел и выдумывал оригинальные задания студентам...
ну, вот - 100500 будильников
Фаджр, Зухр, Аср, Магриб, Иша ? Угадал ?
Время програмируется четырьмя байтами. До 2038 года никаких проблем. 1500 точек * 4 байта = 6000 байт. Сравнивать не очень долго. Несколько милисекунд. Массив спокойно пишется в память программ. Программа преобразования 4 байт в строку и обратно - несколько строк кода. Какие проблемы? Курим unix timestamp.
https://ru.wikipedia.org/wiki/UNIX-%D0%B2%D1%80%D0%B5%D0%BC%D1%8F
Чувак, тут поместить строки во флеш не могут, а ты хочешь чтобы их еще упаковали?
Время програмируется четырьмя байтами.
В данном случае это тоже избыточно.
Достаточно двух байт. Минуты 1-60 это 6 байт Часы 0-24 это 5 байт остается еще 5 байт, которые можно использовать для служебной информации (смена дня, месяца, перевод времени,високосный год и еще что-то это в лоб, хотя 5 байтами можно закодировать не 5,а 32 комбинации). Каждый будильник будет занимать два байта, если не применять какого-то более извращенного кодирования например писать дельту времени между будильниками.
Вот здесь все и хранить
Вот здесь все и хранить
я запретил.
Требую закрыть тему за пропаганду курения!!!
По поводу чувств верующих надо прокосультироваться, но как минимум "Фаджр, Зухр, Аср, Магриб, Иша" уже повод.
Админы вы куда смотрите?
Админы вы куда смотрите?
Дык, собссстнно...
Ещё один вариант:
Всем спасибо. это была задача для студентов. модуля 3231 вообще не оказалось, передавали время по кабелю
Добрый день. Пришёл модуль реального времени ds3231 и проект нужно доделать. Два дня ломал голову, и безрезультатно.На третий день решил написать на форум. Я смог получить дату и время с модуля, но никак не могу сравнить дату, полученную с модуля с датой, взятой из массива, для того чтобы наконец-то сработало условие
Вот код:
1вариант)
Итог -не сравниваются дата полученная с модуля ардуино и дата взятая с массива. Но если проверить, то вот эти обе команды
выдают одинаковые данные - "30.11.2016"
2вариант)Далее попробовал не переводить rtc.getDateStr() в char*:
Результат тот же-не сравнивается, но компилируется без ошибок
3вариант)Далее попробовал перевести дату и элемент массива в строки, и сравнить:
В итоге сравниваются, и после компиляции показывает "ок". Но оказалось что "ок" показывает всегда, даже если элементы не равны друг другу,т.е. я в массиве изменил дату на вчерашнюю и получил "ок", хотя по логике не должно быть так
Может нужна какая-то библиотека для сравнивания?
Вот такой код работает
Но если в массиве много будильников(например 500), то выходит ошибка:
Скетч использует 14 786 байт (45%) памяти устройства. Всего доступно 32 256 байт.
Глобальные переменные используют 11 300 байт (551%) динамической памяти, оставляя -9 252 байт для локальных переменных. Максимум: 2 048 байт.
processing.app.debug.RunnerException: Недостаточно памяти; прочитайте http://www.arduino.cc/en/Guide/Troubleshooting#size
at cc.arduino.Compiler.size(Compiler.java:338)
at cc.arduino.Compiler.build(Compiler.java:158)
at processing.app.Sketch.build(Sketch.java:1111)
at processing.app.Sketch.exportApplet(Sketch.java:1146)
at processing.app.Sketch.exportApplet(Sketch.java:1132)
at processing.app.Editor$DefaultExportHandler.run(Editor.java:2409)
at java.lang.Thread.run(Thread.java:745)
Недостаточно памяти; прочитайте http://www.arduino.cc/en/Guide/Troubleshooting#size
Может как-нибудь с помощью PROGMEM решить проблему? подскажите пожалуйста, кто знает?замучился.