Кто съедает динамическую память?
- Войдите на сайт для отправки комментариев
Пт, 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.
Спасибо за подсказку!
Вот что нашел. По моему это будет удобнее.
Макрос F() Если в коде используется инструкция вроде... Serial.print("Write something on the Serial Monitor"); ...то выводимая на экран строка, как правило, сохраняется в RAM. Таким образом, если в вашем скетче много подобных строк, которые выводятся на Serial Monitor, то ресурс RAM-памяти может закончиться очень быстро. Однако если у вас есть свободное место во flash-памяти, то вышеуказанную инструкцию можно изменить таким образом, чтобы строка сохранялась именно туда. Для этого используется следующий синтаксис: Serial.print(F("Write something on the Serial Monitor that is stored in FLASH"));Удобнее чем что?
Удобнее чем 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 элементов массива
Если еще хочется прооптимизировать код то можно сделать так
126voidpgm_viev(char*name) {/*вывод из PROGMEM*/127charbuffer[15];128strcpy_P(buffer, name);129Serial.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;