Кто съедает динамическую память?
- Войдите на сайт для отправки комментариев
Пт, 09/03/2018 - 00:17
Имеется простейший эмулятор AT команд в котором используются не более 20 переменных типа char.
/****************************************** * Igor Kuznetcov * ATCommand - эмулятор AT команд * * * * *****************************************/ void ExecCMD(char cmd1, char cmd2, int val); //int convert(char ascii[]); void ReadCMD(void); struct ATbuf_t { // Структура команды char cmd1; // команда 1 char cmd2; // команда 2 char ascii_val[4]; // 4 байта данных ascii представление значения int }; ATbuf_t ATbuf; // Буфер команды uint8_t i,j = 0; uint8_t LF = 0x0a; uint8_t CR = 0x0d; boolean state = false; // При успешном приеме команды установить в true // чтение команды с терминала Serial // Предварительно инициализировать скорость терминала Serial.begin(115200) // void ReadCMD() { if (Serial.available() > 0) { char inChar = Serial.read(); //Serial.println(inChar); switch (i) { case 0: if (inChar == 'A') { i++; } else { state = false; } break; case 1: if (inChar == 'T') { i++; } else { i = 0; state = false; } break; case 2: // cmd1 if (inChar == CR) { ATbuf.cmd1 = 0x00; ATbuf.cmd2 = 0x00; for (j = 0; j > 3; j++) {ATbuf.ascii_val[j] = 0x0;}; i = 0; state = true; } else { i++; ATbuf.cmd1 = inChar; } break; case 3: // cmd2 if (inChar == CR) { ATbuf.cmd2 = 0x00; for (j = 0; j > 3; j++) {ATbuf.ascii_val[j] = 0x0;}; i = 0; state = true; } else { i++; ATbuf.cmd2 = inChar; } break; case 4: if (inChar == CR) { for (j = 0; j > 3; j++) {ATbuf.ascii_val[j] = 0x0;}; i = 0; state = true; } else { i++; ATbuf.ascii_val[0] = inChar; } break; case 5: if (inChar == CR) { i = 0; for (j=1; j > 3; j++) { ATbuf.ascii_val[j] = 0; }; state = true; } else { i++; ATbuf.ascii_val[1] = inChar; } break; case 6: if (inChar == CR) { i = 0; for (j=2; j > 3; j++) { ATbuf.ascii_val[j] = 0; }; state = true; } else { i++; ATbuf.ascii_val[2] = inChar; } break; case 7: if (inChar == CR) { i = 0; ATbuf.ascii_val[3] = 0; state = true; } else { i++; ATbuf.ascii_val[3] = inChar; } break; case 8: if (inChar == CR) { i = 0; state = true; } break; } // switch (i) if (state) { state = false; //int val = convert(ATbuf.ascii_val); //Serial.println( val ); ExecCMD(ATbuf.cmd1, ATbuf.cmd2, atoi(ATbuf.ascii_val)); } } } // парсинг AT команд void ExecCMD(char cmd1, char cmd2, int val) { //Serial.println("ExecCMD"); //Serial.print("cmd1, cmd2 = ");Serial.print(cmd1); Serial.print(cmd2); Serial.print(" val = ");Serial.println(val); if (cmd1 == 0x0 && cmd2 == 0x0) { Serial.println("OK"); } else if (cmd1 == 'Z' && cmd2 == 0x0) { Serial.println("Reset to default: OK"); } else if (cmd1 == 'Z' && cmd2 == 'C') { Serial.println("Reset AirComp to default: OK"); } else if (cmd1 == 'Z' && cmd2 == 'F') { Serial.println("Reset BlockFront to default: OK"); } else if (cmd1 == 'Z' && cmd2 == 'R') { Serial.println("Reset BlockRear to default: OK"); } else if (cmd1 == 'Z' && cmd2 == 'V') { Serial.println("Reset Voltage to default: OK"); } else if (cmd1 == 'W' && cmd2 == 0x0) { Serial.println("Write all: OK"); } else if (cmd1 == 'W' && cmd2 == 'C') { Serial.println("Write AirComp: OK"); } else if (cmd1 == 'W' && cmd2 == 'F') { Serial.println("Write BlockFront: OK"); } else if (cmd1 == 'W' && cmd2 == 'R') { Serial.println("Write BlockRear: OK"); } else if (cmd1 == 'W' && cmd2 == 'V') { Serial.println("Write Voltage: OK"); } else if (cmd1 == 'E' && cmd2 == 'C') { if (val == 0 ) { Serial.println("AirComp Disable: OK"); } else { Serial.println("AirComp Enable: OK"); } } else if (cmd1 == 'E' && cmd2 == 'F') { if (val == 0 ) { Serial.println("BlockFront Disable: OK"); } else { Serial.println("BlockFront Enable: OK"); } } else if (cmd1 == 'E' && cmd2 == 'R') { if (val == 0 ) { Serial.println("BlockRear Disable: OK"); } else { Serial.println("BlockRear Enable: OK"); } } else if (cmd1 == 'E' && cmd2 == 'V') { if (val == 0 ) { Serial.println("Voltage Disable: OK"); } else { Serial.println("Voltage Enable: OK"); } } else if (cmd1 == 'D' && cmd2 == '0') { Serial.println("Debug Level0: OK"); } else if (cmd1 == 'D' && cmd2 == '1') { Serial.println("Debug Level1: OK"); } else if (cmd1 == 'D' && cmd2 == '2') { Serial.println("Debug Level2: OK"); } else if (cmd1 == 'P' && cmd2 == '?') { Serial.print("P = "); Serial.println("8.0"); } else if (cmd1 == 'P' && cmd2 == '0') { Serial.print("Pmin = "); Serial.println(val); } else if (cmd1 == 'P' && cmd2 == '1') { Serial.print("Pmax = "); Serial.println(val); } else if (cmd1 == 'P' && cmd2 == 'B') { Serial.print("Pblock = "); Serial.println(val); } else if (cmd1 == 'C' && cmd2 == 'T') { Serial.print("AirComp T = "); Serial.println(val); } else if (cmd1 == 'S' && cmd2 == '?') { Serial.print("Speed = "); Serial.println("10"); } else if (cmd1 == 'F' && cmd2 == '?') { Serial.print("BlockFront = "); Serial.println("OFF"); } else if (cmd1 == 'F' && cmd2 == '0') { Serial.print("BlockFront VmaxOn = "); Serial.println(val); } else if (cmd1 == 'F' && cmd2 == '2') { Serial.print("BlockFront VautoOff = "); Serial.println(val); } else if (cmd1 == 'R' && cmd2 == '?') { Serial.print("BlockRear = "); Serial.println("OFF"); } else if (cmd1 == 'R' && cmd2 == '0') { Serial.print("BlockRear VmaxOn = "); Serial.println(val); } else if (cmd1 == 'R' && cmd2 == '2') { Serial.print("BlockRear VautoOff = "); Serial.println(val); } else if (cmd1 == 'V' && cmd2 == '?') { Serial.print("Voltage = "); Serial.println("12"); } else if (cmd1 == 'V' && cmd2 == 'M') { Serial.print("Voltage min= "); Serial.println(val); } else if (cmd1 == 'I' && cmd2 == 'C') { Serial.print("AirComp Enable = "); Serial.println("1"); Serial.print("AirComp State = "); Serial.println("RUN"); Serial.print("AirComp Pressure = "); Serial.println("8.0"); Serial.print("AirComp Pmax = "); Serial.println("8.5"); Serial.print("AirComp Pmin = "); Serial.println("6.5"); Serial.print("AirComp Pblock = "); Serial.println("6.0"); Serial.print("AirComp Tmax = "); Serial.println("1200"); } else if (cmd1 == 'I' && cmd2 == 'F') { Serial.print("BlockFront Enable = "); Serial.println("1"); Serial.print("BlockFront State = "); Serial.println("OFF"); Serial.print("BlockFront VmsxBlockOn = "); Serial.println("0"); Serial.print("BlockFront VautoBlockOff = "); Serial.println("20"); } else if (cmd1 == 'I' && cmd2 == 'R') { Serial.print("BlockRear Enable = "); Serial.println("1"); Serial.print("BlockRear State = "); Serial.println("OFF"); Serial.print("BlockRear VmsxBlockOn = "); Serial.println("0"); Serial.print("BlockRear VautoBlockOff = "); Serial.println("20"); } else if (cmd1 == 'I' && cmd2 == 'V') { Serial.print("Voltafe Enable = "); Serial.println("0"); Serial.print("Voltafe Current = "); Serial.println("12.4"); Serial.print("Voltafe Critical = "); Serial.println("10.0"); } else if (cmd1 == 'I' && cmd2 == 'S') { Serial.print("Speed = "); Serial.println("0"); } } /* int convert(char ascii[]) { return atoi(ascii); } */ void setup() { // put your setup code here, to run once: Serial.begin(115200); } void loop() { // put your main code here, to run repeatedly: ReadCMD(); }
При компиляции
Скетч использует 6232 байт (21%) памяти устройства. Всего доступно 28672 байт. Глобальные переменные используют 1190 байт (46%) динамической памяти, оставляя 1370 байт для локальных переменных. Максимум: 2560 байт.
Кто съедает память?
Ох, сердце вещует, строчки в кавычках.
Думаю, что память жрут многочисленные строковые константы.
А вот условия циклов в строках 75, 86 и 96 - это сильно! Нипадецки вставляет :) Эта программа не для LSD случаем? :)))))
Кто съедает память?
Строк в кавычках - более 60-ти. Даже если они в среднем всего по 15 символов - уже порядка тысячи байт сожрали.
Кто съедает память?
Строк в кавычках - более 60-ти. Даже если они в среднем всего по 15 символов - уже порядка тысячи байт сожрали.
Как тогда сохранить строки, что бы они так не пожирали память?
Думаю, что память жрут многочисленные строковые константы.
А вот условия циклов в строках 75, 86 и 96 - это сильно! Нипадецки вставляет :) Эта программа не для LSD случаем? :)))))
Нет, не для LSD
Таким способом думаю настройки делать в готовом приборе.
Знаю, что есть какая-то функция, что массив обнуляет, но на память не помню и оставил это на "потом".
Но как я понял - проблема в большом количестве строковых значений.
Можно их как-то иначе записать, что бы они не съедали столько памяти?
А сколько динамической памяти считается нормальным для работы?
Можно их как-то иначе записать, что бы они не съедали столько памяти?
Ищите по ключевому слову PROGMEM.
Спасибо за подсказку!
Вот что нашел. По моему это будет удобнее.
Удобнее чем что?
Удобнее чем PROGMEM, нет?
PROGMEM ? Неудобно : Удобно ;
F ? Удобно : Неудобно ;
Ночью уже доделывал и выражение туманных мыслей обернулось в такой оборот :)
В общем оптимизировал со строками. Во первых я их укоротил существенно и вывожу в Serial.print с использованием макроса F()
С учетом прочих оптимизаций код программы уменьшился, а использование динамической памяти снизилсоь с 94% до 24% :)
Под словом "удобно" я имел в виду результат. Извиняюсь за мой французский :)
И спасибо всем откликнувшимся!
эээххх... учится и учиться еще
Думаю, что память жрут многочисленные строковые константы.
А вот условия циклов в строках 75, 86 и 96 - это сильно! Нипадецки вставляет :) Эта программа не для LSD случаем? :)))))
Спасибо за подсказку. Это конечно ошибка из-за невнимательности
Правильно: for (j = 0; j < 4; j++) {ATbuf.ascii_val[j] = 0x0;};
Знаю, что есть какая-то функция, что массив обнуляет
memset
Можно их как-то иначе записать, что бы они не съедали столько памяти?
В дополнение к тому, что Вам уже посоветовали про PROGMEM (именно в дополнение, а не вместо), посмотрите сколько раз у Вас хранятся одинаковые подстроки, в разных фразах. Например,
BlockFront - 11 раз
BlockRear - 11 раз
Write - 7 раз
Reset - 5 раз
Так храните их 1 раз. Это потребует 2-х Serial.print вместо одного (сначала вывести общую часть, а потом хвост), но память под строки сократит существенно.
Правильно: for (j = 0; j < 4; j++) {ATbuf.ascii_val[j] = 0x0;};
Вот и отлично, что Вы это сами нашли!
Знаю, что есть какая-то функция, что массив обнуляет
memset
Можно их как-то иначе записать, что бы они не съедали столько памяти?
В дополнение к тому, что Вам уже посоветовали про PROGMEM (именно в дополнение, а не вместо), посмотрите сколько раз у Вас хранятся одинаковые подстроки, в разных фразах. Например,
BlockFront - 11 раз
BlockRear - 11 раз
Write - 7 раз
Reset - 5 раз
Так храните их 1 раз. Это потребует 2-х Serial.print вместо одного (сначала вывести общую часть, а потом хвост), но память под строки сократит существенно.
Да, я это тоже увидел и уже исправил. В большинстве вообще убрал эти строки оставив только ОК, который тоже превратил
const char OK[]="OK";
А вот использовать memset в моем случае не везде удобно. В некоторых строках я обнуляю только часть массива. Пусть уже будет однотипно. Читается для меня легче. И думаю, что memset не сильно по ресурсам будет отличаться от for... для 4 элементов массива
Если еще хочется прооптимизировать код то можно сделать так
126
void
pgm_viev(
char
*name) {
/*вывод из PROGMEM*/
127
char
buffer[15];
128
strcpy_P(buffer, name);
129
Serial
.print(buffer);
130
}
Смотрите здесь #257
А вот использовать memset в моем случае не везде удобно. В некоторых строках я обнуляю только часть массива. Пусть уже будет однотипно. Читается для меня легче. И думаю, что memset не сильно по ресурсам будет отличаться от for... для 4 элементов массива
А вот memset() определённо лучше.
Даже в смысле читаемости кода:
Правильно: for (j = 0; j < 4; j++) {ATbuf.ascii_val[j] = 0x0;};
Даже когда это произвольные части массива.
В некоторых строках я обнуляю только часть массива.
И что? memset-то чем виноват, сколько нужно, столько и обнуляйте.
И думаю, что memset не сильно по ресурсам будет отличаться от for... для 4 элементов массива
Будет отличаться, скорее всего НЕ в пользу memeset'а
если хотите круто оптимизироваться, то для 4-х значений лучше написать безо всякого цикла:
a[0] =a[1] = a[2] = a[3] = 0;
И всего делов.
Можно ещё короче (суть та же)
*((long *)(ATbuf.ascii_val)) = 0;