Помогите со стрингами! :)

pliz
Offline
Зарегистрирован: 30.05.2017

Добрый день!

 

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

 

Преамбула.

У меня нет программистского образования, но за свою жизнь сталкивался достаточно много - и в институте в лаборатории параллельно работал, писали СУБД бухгалтерскую, и на ПХП для сайта какую-то простейшую обработку тестов-опросников делал. Но - на ассемблере не писал и в отношении Си мой опыт был где-то на уровне "привет мир!"

Заинтересовался Ардуинками, начал разбирася с C#.  Ковырялся со всякими более-менее простыми задачками - начиная с блинка и далее со всякими датчиками и устройствами. Ну вообщем-то для того, чтобы что-то изучить - надо найти для себя интересную задачу и постараться её решить и реализовать. Решил собрать высотомер-логгер - в простом варианте - включаясь, вычисляет на BMP280 высоту, присваевает переменной текущей высоты значение измеренной высоты (то есть текущая высота будет теперь привязана к нулю). И выводит значение температуры и высоты на дисплей 5110 84x84 LCD. И - пишет в файл строку с датой-временем и с текущей высотой (первая высота = 0). И далее в void loop при изменении высоты - выводит показания на экран и записывает в файл новую строку. Ну и естественно всё это завязано на RTC на DS1307, откуда берётся время.

 

"Амбула". Требующая "амбуланса" - "лечения".

Вначале я вообще хотел формировать строковую переменную - название файла - из текущего времени, полученного с RTC во время запуска - выполнения сетапа. Но - видно что-то я делаю не так, и создаётся впечатление, что строковые переменные "перегружают" память и ардуинка сходит с ума. Сейчас - название файла просто прописано заранее. Так - работает.

Мой вопрос заключается в том, как проще и правильнее обходиться с "текстовой" (?) информацией, как её "передавать" от устройства к устройству - в схеме - или "от объекта объекту - в программе"? может быть это неправильно, что я стал использовать String? возможно - это отжирает память? у меня и так получается большой код, в Ардуино Нано 168 - не умещается, только в Уно.

 

Вот код - который "работает если не включать ничего в void loop. Лишнее (работа с экраном и запись на СД - убрал пока из кода - там проблем сейчас нет, всё работает).

Пробовал переписывать код. Я до этого делал, что функция была "вынесена" - и вызываясь, возвращала значение в виде строки и присваивалось переменной (myTimeStamp = digitalClockString();). Решил - "меньше переменых" - думал если сразу "пихать информацию в строку" - то будет лучше работать - ан, нет.

В каком направлении "копать" - наставьте на путь истинный!

 


/*
* TimeRTC.pde
* example code illustrating Time library with Real Time Clock.
*
*/

#include <TimeLib.h>
#include <Wire.h>
#include <DS1307RTC.h>  // a basic DS1307 library that returns time as a time_t
//

String myTimeStamp;
String mySaveFile;

void setup()
{
    // Open serial communications and wait for port to open:
    Serial.begin(9600);
    while (!Serial) {
        ; // wait for serial port to connect. Needed for native USB port only
    }

    // RTC has set the system time:
    setSyncProvider(RTC.get);   // the function to get the time from the RTC

    digitalClockString();
    mySaveFile = myTimeStamp;
    Serial.print("Startup (setup) TimeStamp: ");
    Serial.println(myTimeStamp);
    Serial.println();
    Serial.print("Startup (setup) mySaveFile: ");
    Serial.println(mySaveFile);
    Serial.println();


    delay(4000);
    digitalClockString();
    Serial.print("Delayed TimeStamp: ");
    Serial.println(myTimeStamp);

}

void loop()
{
// если включить эти строки - то код грузится, но ардуино - зависает и не выдает ничего в компорт.
//    delay(4000);
//    digitalClockString();
//    Serial.print("Delayed TimeStamp: ");
//    Serial.println(myTimeStamp);


}




/****************************************************************************/
/*****************all of my functions are down there*************************/
/****************************************************************************/



char digitalClockString() {
    // digital clock display of the time
    myTimeStamp = "";
    if (hour() < 10) myTimeStamp.concat("0");
    myTimeStamp.concat(hour());
    myTimeStamp.concat(":");
    if (minute() < 10) myTimeStamp.concat("0");
    myTimeStamp.concat(minute());
    myTimeStamp.concat(":");
    if (second() < 10) myTimeStamp.concat("0");
    myTimeStamp.concat(second());
    myTimeStamp.concat("_");

    if (day() < 10) myTimeStamp.concat("0");
    myTimeStamp.concat(day());
    myTimeStamp.concat("-");
    if (month() < 10) myTimeStamp.concat("0");
    myTimeStamp.concat(month());
    myTimeStamp.concat("-");
    myTimeStamp.concat(year());

    return 0;
}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

pliz пишет:

Заинтересовался Ардуинками, начал разбирася с C#.  

В каком направлении "копать" - наставьте на путь истинный!

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

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

63 строка void digitalClockString() {

84 удалите нахрен.

Перед 17 строкой добавьте myTimeStamp.reserve(20);

Объясните мне и себе зачем вам переменная mySaveFile.

И внимательно прочитайте то что написал ЕвгенийП.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

ПС: Язык он здесь в минимуме http://arduino.ru/Reference

Или здесь в углубленом виде http://cpp.com.ru/kr_cbook/index.html#content

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

просто изучите коды библиотеки RTC и примеров, в которых УЖЕ сделан вывод даты в строковом виде, например Rtc_by_Makuna.

ессно, на аглицком.

pliz
Offline
Зарегистрирован: 30.05.2017

brokly, спасибо!

Вообщем-то самый толковый и по делу комментарий. То что вы написали - попробую вечерком подпавить, да, "даже странно что так написал". Видно - вылезло, когда для себя разбирался и пытался продифференцировать "переменную", "объект", "метод-процедуру/функцию".

И про reserve() - спасибо, интуитивно понимал, что "что-то с памятью моей стало" - но как её "зарезервировать" - не знал...

>> Объясните мне и себе зачем вам переменная mySaveFile.

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

wdrakula - спасибо за наводку на эту библиотеку РТС (Макуна) - у меня несколько других скачано и установлено, я и учился по примерам - сейчас посмотрю примеры в этой библиотеке - может быть действительно чего для себя найду того, что будет доступно моему разумению.

С английским проблем нет, наоборот иногда какие-то технические вещи проще на английском прочитать - более точно.

Так что - пока что всем большое спасибо, буду "грызть дальше".

pliz
Offline
Зарегистрирован: 30.05.2017

Просто иногда - "не хватает опыта понять - где искать проблему"... я тут месяц назад убил день на попытки подключить 5110 84x84 LCD - что только не перепробовал... пока не выяснилось, что один из двух имевшихся в наличии дисплеев был "дохлым" - и гребёнку я запаял и соответственно "игрался" - с этим "дохлым"... Интерфейс-то у него работал, с ардуинкой общался по И2С - но только ничего не показывал. А я думал - что я неправильно библиотеку подключаю или ещё чего-то не так делаю. :)

pliz
Offline
Зарегистрирован: 30.05.2017

brokly пишет:

63 строка void digitalClockString() {

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

Но всё равно - без "резервирования памяти" - "что-то шло не так".

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

* * *

Нескромный вопрос - (книжку со временем почитаю) - а что, получается что в Си для строковых объектов надо вот так вот в явном виде определять область памяти? я пробовал добиться этого же изначальным присвоением при инициализации им некоторых значений - но это не давало результата...

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Жесть. Прочел бы книгу, меньше вопросов было. Вот вы собираетестесь толпой на курорт. Места надо явно заказывать,звоня что бы там вам подготовили места, или же забить на все ,приехать  и узнать что часть народа будет спать на улице. И еще есть строковые константы и строковые переменные. Первые храняться в памяти программы, а вторые в памяти ОЗУ.

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Ну если памяти немерянно, то ее расход можно не контролировать. У ардуино память ограничена. Тут на сайте есть исследования ЕвгенияП, там доходчиво объяснено в чем косяк String. Вообще нужно знакть как си использует память, как правило все реализовано через кучи и "базовые" функции динамического выделения памяти malloc(). Если же вы четко знаете размер нужной вам переменной и правильно описываете ее, то помимо некоторой экономии памяти получаете возможность хранить ее в стеке. В общем это не "популярное" разъяснение, не смогу в двух словах объяснить. 

Родной способ оперирования текстовыми строками это массив чаров, стринг сделан для облегчения работы со строками и как минус, не найден способ полного контроля над памятью. Если часто "дергать" стринг, то в большинстве случаев куча будет сильно дефрагментироватся и из оборота будут выпадать мелкие куски, они вроде как свободны, но никому не нужны. Отсюда и нехватка памяти.

Кстати да если Serial.print("Delayed TimeStamp: "); записать как Serial.print(F("Delayed TimeStamp: ")); вы заставите компилятор сохранять текстовые данные в памяти программы, а озу оставите свободным от этой длинно и ненужной строки.

https://www.arduino.cc/en/Reference/PROGMEM

 

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

#include <time.h>

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

pliz пишет:

Нескромный вопрос - (книжку со временем почитаю) -

Прекращаёте наглеть-то. Вам сказали что прочитать, так и читайте. Людям заняться нечем, кроме как перепечатывать здесь содержимое книг, которые Вы "со временем почитаете"?

На Ваш вопрос, я "со временем отвечу".

pliz
Offline
Зарегистрирован: 30.05.2017

brokly пишет:
Тут на сайте есть исследования ЕвгенияП, там доходчиво объяснено в чем косяк String.
В "прикреплённых темах"? читал, перед тем как задавать свой вопрос. В приложении к своей ситуации по тому материалу выводов для себя не сделал...

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

brokly пишет:
Вообще нужно знакть как си использует память, как правило все реализовано через кучи и "базовые" функции динамического выделения памяти malloc(). Если же вы четко знаете размер нужной вам переменной и правильно описываете ее, то помимо некоторой экономии памяти получаете возможность хранить ее в стеке. В общем это не "популярное" разъяснение, не смогу в двух словах объяснить.
Да, "работа с память" - это то, с чем мне нужно будет разбираться, если продолжать пытаться дальше ковыряться с программированием на Си. Какие-то общие принципы - вроде понятны, но надо будет устроить себе - "лабораторную работу". Я лучше запоминаю и понимаю, когда это руками сделаю.

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

brokly пишет:
Родной способ оперирования текстовыми строками это массив чаров, стринг сделан для облегчения работы со строками и как минус, не найден способ полного контроля над памятью. Если часто "дергать" стринг, то в большинстве случаев куча будет сильно дефрагментироватся и из оборота будут выпадать мелкие куски, они вроде как свободны, но никому не нужны. Отсюда и нехватка памяти.
Идею примерно понимал. Потому и пытался уйти от стрингов к чар-массивам. Но - когда ковырялся - почему-то не помогло.

Сейчас - всё в порядке!

brokly пишет:
Кстати да если Serial.print("Delayed TimeStamp: "); записать как Serial.print(F("Delayed TimeStamp: ")); вы заставите компилятор сохранять текстовые данные в памяти программы, а озу оставите свободным от этой длинно и ненужной строки.
Спасибо, буду знать.

Но все эти строки нужны мне только на этапе отладки, когда всё будет собрано/спаяно и будет работать - всё это можно будет спокойно убрать, я это оставлял в первую очередь для того, чтобы понимать - "до какого момента программа доходит и на чём подвисает". Как-то я пока не научился более эффективно дебаггером пользоваться в VisualMicro.

brokly - ещё раз спасибо вам большое!

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

qwone пишет:

И еще есть строковые константы и строковые переменные. Первые храняться в памяти программы, а вторые в памяти ОЗУ.

Вот с этого момента поподробнее, пожалуйста.

Logik
Offline
Зарегистрирован: 05.08.2014

pliz пишет:

...

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

Да заметили Вы все. Только признатесь себе боитесь. Все эти либки , от stl до boost включая Strings всех пород - хрень несусветная, расчитаные на лохов поведущихся на шаровой код, они даже рядом не лежали с эффективной реализацией грамотного разраба. Пишите код сами, не расчитывайте на шару, так у вас возникнет понимание происходящего (Вам лично +10 в карму;) и эффективность решения - как побочный продукт понимания сущностей.

bwn
Offline
Зарегистрирован: 25.08.2014

andriano пишет:

qwone пишет:

И еще есть строковые константы и строковые переменные. Первые храняться в памяти программы, а вторые в памяти ОЗУ.

Вот с этого момента поподробнее, пожалуйста.

Увы, сие кочует по всей научно-популярной литературе для непрограммистов. И ведь веришь, пока не доберешься до этих граблей.((((

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

bwn пишет:
Увы, сие кочует по всей научно-популярной литературе для непрограммистов. И ведь веришь, пока не доберешься до этих граблей.((((

Ну а это что?

char *pnt = "ctroka";
char  aaa[] = "ctroka";