Кстати, я почему то не нашел объяснения для чего нужны константы. Коллизия, объявлена как константа а храниться в ОЗУ. Хотя можем принудительно пихнуть ее во флешь, но тогда работать с ней придется с подвывертом (понимая, что это и почему).
Прежде всего const это спецификатор. И он сообщает что данная величина используется только для чтения. А уже потом компилятор решает как компактно и эфеективно ее разместить. Из этого не следует что const это обязательно константа. Так же #define не делает что-то константой . И вот еще мой вариант который мне больше нравится
Cl_AAA AAA(/*константа*/12);
И это тоже константа, но без всяких const и #define. Простенько и если надо можно на месте поменять.
Кстати, я почему то не нашел объяснения для чего нужны константы. Коллизия, объявлена как константа а храниться в ОЗУ. Хотя можем принудительно пихнуть ее во флешь, но тогда работать с ней придется с подвывертом (понимая, что это и почему).
Прежде всего const это спецификатор. И он сообщает что данная величина используется только для чтения. А уже потом компилятор решает как компактно и эфеективно ее разместить. Из этого не следует что const это обязательно константа. Так же #define не делает что-то константой . И вот еще мой вариант который мне больше нравится
Cl_AAA AAA(/*константа*/12);
И это тоже константа, но без всяких const и #define. Простенько и если надо можно на месте поменять.
Все так спорно... так спорно... Нахрена константу "МЕНЯТЬ НА МЕСТЕ" (!!!) это же константа !!!!!!!
const и правда спецификатор, это не откровение, имхо, ни для кого :)
Компилятор ничего не решает, он разместит ее в озу :)
И на десерт, понятие константа означает - постоянный, неизменный :)
И кстати... Cl_AAA AAA(/*константа*/12); - что это за бред?
Что спорно? В языке Си нет инструмента объявления только для образования констант. Или пользоваться макросом, или спецификатором const. Но и то и другое объявляет не только константы.
/**/
void func (const int a) { // <- a должна быть константой
/*но только внутри функции,а снаружи это переменная*/
const int b = 5; //<- константа , и распостранена только внутри функции
/* в отличии от #define - который не возжно огаричить, если его уже объявили */
}
void setup() {
10; 0x5; B0001;//<- это все 100% константы, а остальное может быть а может нет.:)
int c = 5; //
func(c);
int const * const p = &c; //Запрет изменять и хранимый в указателе "p" адрес,
}
void loop() {
}
/*Скетч использует 444 байт (1%) памяти устройства. Всего доступно 32256 байт.
Глобальные переменные используют 9 байт (0%) динамической памяти, оставляя 2039 байт для локальных переменных. Максимум: 2048 байт.
*/
/**/
class Cl_AAA {
const int a;
public:
Cl_AAA(const int a_): a(a_) {}
};
Cl_AAA AAA(/*константа*/12);//<- чего странного, Вы что не знаете, что константу можно прямо записать числом О_О
void setup() {
}
void loop() {
}
/*Скетч использует 494 байт (1%) памяти устройства. Всего доступно 32256 байт.
Глобальные переменные используют 11 байт (0%) динамической памяти, оставляя 2037 байт для локальных переменных. Максимум: 2048 байт.
*/
В этом вашем лживом С++ никада нельзя сказать точно, что сегодня с утра означает оператор присваивания. А вы тут про медленно меняющиеся константы....
Я, када встретил в одном коде #define FALSE TRUE, две недели пилъ беспробудно.
Зато туева хуча человеков стандарты выдумывает, уже Х томов понаписали. Мне эта ситуация почему-то напоминает поговорку "У семи нянек - дитя без глазу". Только тут икспердов-нянек гораздо больше чем семь, поэтому дитя у них, не успеешь отвернуца, не то что без глазика, а вапще валяется покрошенное в фарш.
и что вы тут поменяли на лету и что такое "/*пин A*/2" и далее
ЕвгенийП пишет:
Это ещё ничо. Ессть языки, где вся эта хрень может изменяться по ходу выполнения программы.
я не спец, но ни одного языка высокого уровня окромя убогово javascript я не видел возможность изменения предопределенной константы. Есть только в C++ (за C не скажу) и производных возможность снять признак постоянства. Но обычно в жизни считается подобное мерой крайней и не культурной. Хотя сам по себе язык такое позволяет.
А ну и конечно случаи не корректной передачи данных внутрь вызываемых функций (когда передают как сами данные, так и казатель на них, а внутри рабоитают, если грубо, то с обратной стороны).
Чего не даст? Константу поменять? А кто его спрашивать-то будет? :)
sirota пишет:
убогово javascript
Фига се! Это про язык с динамическим полиморфизмом и прототипным наследованием? Боюсь, что использованное Вами прилагательное больше отражает уровень Ваших знаий о JavaScript, чем природу языка.
sirota пишет:
я не видел возможность изменения предопределенной константы.
В старом добром Фортране IV это была штатаная фича. Причём менялась константа как таковая (например 5 становилось равным 3 или там 10). И, повторяю, это была не особенность реализации, а штатная фича. В таком виде Фортран существовал десятилетиями. Ушло это только в новых стандартах, причём обычно есть опция "вернуть" для совместимости с миллиардами строк кода, написанных на Фортране.
sirota пишет:
в жизни считается подобное мерой крайней и не культурной.
Вообще, изначально в своей реплике я противопоставил #define - const, говоря о том, что такой прием, часто позволяет съэкономить оперативку, а иногда ускориться, и уже как на побочку намекнул на некую нестыковку самого определения константы и возможных с ней операций :) Естественно все это в приложении к ардуино.
В этом вашем лживом С++ никада нельзя сказать точно, что сегодня с утра означает оператор присваивания. А вы тут про медленно меняющиеся константы....
Я, када встретил в одном коде #define FALSE TRUE, две недели пилъ беспробудно.
Зато туева хуча человеков стандарты выдумывает, уже Х томов понаписали. Мне эта ситуация почему-то напоминает поговорку "У семи нянек - дитя без глазу". Только тут икспердов-нянек гораздо больше чем семь, поэтому дитя у них, не успеешь отвернуца, не то что без глазика, а вапще валяется покрошенное в фарш.
Мелочи. Уже приводил тут примерчик из реального и не мелкого проекта, что-то типа так:
Ну, почему сразу засада. Если по жизни стояла задача: "Если p, то с вероятностью 0,1 выполнить ...", то конструкция как конструкция. Прокомментировать как следует и, когда станет не нужна, выбросить #undef'ом. Хотя, я бы делал это по-другому.
Пытаетесь программировать на языке, которого не знаете и знать не хотите (ни одна нормальная книжка по языку Вами не прочитана).
Целочисленное деление в этом языке производится с отбрасванием остатка, каким бы он ни был. Результат всегда целый. Например, 200/200 и 300/200 и 399/200 - результат один и тот же, а именно - 1.
Указатель стека называется SP. Он доступен в любой момент. Т.е. запомните его в началеа потом посмотрите в нужной точке и, вычтя одно из другого, узнаете какой стек Вы уже накопили.
В принципе, вот в этой теме, в конце первого поста, есть программа Memory Explorer. Она печатает и стек, и кучу, и свободные куски.
Вы дали слишком мало информации, чтобы можно было ответить конкретно. Но, в целом, если Вы не понимаете какой модуль отжирает, попробуйте
1. Назначить свой фолдер build
2. После компиляции посмотрите в него и во все его подфолдеры. Там будут файлы с названиями Ваших модулей (и библиотечных, и системных тоже) с расширением ".o" - это скомпилированные файлы модулей.
Вот и смотрите какой из них какого размера. Это не точно, но общее представление даст.
Спасибо! тут всё просто : Sketch uses ... (91%) of program storage space. вот и вся информация.
Ее уже достаточно что-бы задуматься.
В папочке \arduino_bulid_xxxxx\ всем-известные библиотеки Wire, SPI, RadioHead
Гораздо интереснее в папке \core
Там откуда-то взялись HardwareSerial.cpp.*, USBCore.cpp.* и IPAddress.cpp.*
100% нигде у меня они не подключены, и не могут быть подключены, интересно, где посмотреть кто их за собой тянет?
Посмотрите на скетчи, опубликованные здесь на форуме. Если Вы где-то найдёте глобальную переменную или функцию, объявленную как static - это большая редкость. Между тем, если переменная или функция не вызываются из других файлов, нет никаких причин не объявить их статическими, ну вообще никаких. Люди этого не делают просто из лени, а большинство из непонимания возможных выгод от этого.
Но ведь под статические переменные память резервируется сразу и нет возможности использовать "временно неиспользуемую" память под сиюминутную нужду (большой буфер необходимо сформировать, например). Или таки это плюс, а не минус?
Последнее использование static— глобальная переменная в файле кода. В этом случае использование staticуказывает, что исходный код в других файлах, которые являются частью проекта, не может получить доступ к переменной. Только код внутри того же файла может увидеть переменную (её область видимости ограничена файлом). Эта техника может быть использована для моделирования объектно-ориентированного кода, потому что она ограничивает видимость переменных и таким образом помогает избежать конфликта имен. Этот способ использования staticявляется пережитком Cи.
А, ну теперь понятно. Я столько глобалов не создаю, чтобы прям запутаться в них (вообще редко создаю), поэтому статик только для сохранения значений внутри функции использовал (и подумал, что лажаю с ним, если не ставлю везде )). Ну и... паттернализм, вобщем - что всегда делаем, о том постоянно и думаем.
И это даёт оптимизатору право смело выбрасывать переменную (или переводить её в регистр, а то и в непосредственное значение), если в этом файле она не нужна, т.к. из других файлов она не доступна.
А вот если она не статик, то компилятор не может её выбросить, т.к. вдруг она из другого файла используется? В этом случае её может выбросить только линкер.
Ну, а поскольку алгоритмы оптимизаторов сложны и порой непредсказуемы, два шанса выбросить - лучше, чем один.
Т.е. объявляя её static, мы помогаем оптимизатору.
Тоже касается и функций. Если функция глобальна и Вы не планируете использовать её из других файлов - не скрывайте этого от оптимизатора - объявите static. Он её может в inline засунет или, если Вы перестали её использовать, запросто вообще выбросит.
Большинство моих классов полностью статические, т.е. все поля и методы у них объявлены как static, всё что static const и более-менее крупное - объявлено как PROGMEM. Никаких #define для констант - только static const с контролем типов.
>Почему преимущественно статические классы ?
<А для того чтобы не создавать экземпляров, у меня на плате только один LCD-экран, одни RTC-часы и т.д. зачем мне дурацкие конструкторы, передающие номера пинов, запоминающие эти пины в оперативке(а именно так и происходит в большинстве библиотек), -хотя вся конфигурация известна на момент компиляции.
Но, бездумно тыкая везде static я забыл что элементы-то меню у меня динамически создаются и тут я профукал 78 байт оперативки на ровном месте, а таких мест десятки.
Делаю менюшку в одном варианте все получилось (но там все переменные должны быть одинакового типа), не очень удобно, а во втором варианте, не получается получить (и вывести) значение параметра. Можете подсказать синтаксис и вообще, может через неопределенный тип это опасно делать?
// -------Параметры, выбираемые в меню --------
float tComfSummer = 23.5; // летняя температура комфорта в комнате !!!!!!!!!!!!!!!
float tComfWinter = 24.4; // зимняя температура комфорта в комнате !!!!!!!!!!!!!!
byte tInpStr = 45; // средняя температура подачи теплоносителя
byte timeQuer = 15; // Время опроса датчиков
boolean Pump = 1 ; // контроль циркуляционного насоса 1- вкл, 0 выкл !!!!!!!!!!!!!!
//-----------------------------------------------
typedef struct _procesBut {
void(*on_click)(char);
void *param; //!!!!!!!!!!!! ВОПРОС ПО ЭТОМУ ПАРАМЕТРУ
String title;
} ProcesBut;
ProcesBut procesButs[] = {
{Edit_tPrmComfSummer, &tComfSummer, "tLeto: "}, // летняя температура комфорта в комнате !!!!!!!!! указал ссылки на перемен
{Edit_tPrmComfWinter, &tComfWinter, "tSima: "}, // зимняя температура комфорта в комнате !!!!!!!!! указал ссылки на перемен
{Edit_tInpStr, &tInpStr, "tPod: "}, // средняя температура подачи теплоносителя !!!!!!!!! указал ссылки на перемен
{Edit_tInpStr, &timeQuer, "vrOpr: "}, // время опроса (задействуем туже функцию что и в темп.подачи)
{SettingPump, &Pump, "Nasos: "} // контроль циркуляционного насоса !!!!!!!!! указал ссылки на перемен
};
///----------- код (снятие показаний, обработка параметров и т.д.)
// не получается (не знаю и возможно ли это вообще? ) получить
// procesButs[NomParam].param ???
Ну, это можно делать миллионом способов, причем способы сильно отличаются по изящности и требованиям к знанию и пониманию языка. Я покажу Вам один из самых топорных способов, преимущество которого в том, что он требует минимальных изменений Вашего кода.
Суть в том, чтобы помнить какой тип изначально был указан и в любой обработке это учитывать. Я привел пример обработки – преобразование к строке, пример полностью рабочий, можете запускать.
// -------Параметры, выбираемые в меню --------
float tComfSummer = 23.5; // летняя температура комфорта в комнате !!!!!!!!!!!!!!!
float tComfWinter = 24.4; // зимняя температура комфорта в комнате !!!!!!!!!!!!!!
byte tInpStr = 45; // средняя температура подачи теплоносителя
byte timeQuer = 15; // Время опроса датчиков
boolean Pump = 1 ; // контроль циркуляционного насоса 1- вкл, 0 выкл !!!!!!!!!!!!!!
//-----------------------------------------------
enum ParamType { PT_FLOAT, PT_BYTE, PT_BOOL }; // Перечисляем все возможные типы
typedef struct _procesBut {
ParamType pType;
_procesBut(void(*cb)(char), float * p, const char *st) : on_click(cb), param(p), title(st) { pType = PT_FLOAT; }
_procesBut(void(*cb)(char), byte * p, const char *st) : on_click(cb), param(p), title(st) { pType = PT_BYTE; }
_procesBut(void(*cb)(char), bool * p, const char *st) : on_click(cb), param(p), title(st) { pType = PT_BOOL; }
void(*on_click)(char);
void *param; //!!!!!!!!!!!! ВОПРОС ПО ЭТОМУ ПАРАМЕТРУ
String title;
// Для примера - как с этим работать - преобразование к строке
char * toString(void) {
static char sBuffer[7];
static const int8_t buffSize = sizeof(sBuffer) - 1;
switch(pType) {
case PT_FLOAT:
dtostrf(*(float *)param, -buffSize, 1, sBuffer);
break;
case PT_BYTE:
utoa(*(byte *)param, sBuffer, 10);
break;
case PT_BOOL:
strcpy(sBuffer, *(bool *)param ? "Yes" : "No");
break;
}
return sBuffer;
}
} ProcesBut;
void Edit_tPrmComfSummer(char) {}
void Edit_tPrmComfWinter(char) {}
void Edit_tInpStr(char) {}
void SettingPump(char) {}
ProcesBut procesButs[] = {
ProcesBut(Edit_tPrmComfSummer, &tComfSummer, "tLeto: "), // летняя температура комфорта в комнате !!!!!!!!! указал ссылки на перемен
ProcesBut(Edit_tPrmComfWinter, &tComfWinter, "tSima: "), // зимняя температура комфорта в комнате !!!!!!!!! указал ссылки на перемен
ProcesBut(Edit_tInpStr, &tInpStr, "tPod: "), // средняя температура подачи теплоносителя !!!!!!!!! указал ссылки на перемен
ProcesBut(Edit_tInpStr, &timeQuer, "vrOpr: "), // время опроса (задействуем туже функцию что и в темп.подачи)
ProcesBut(SettingPump, &Pump, "Nasos: ") // контроль циркуляционного насоса !!!!!!!!! указал ссылки на перемен
};
static int8_t TotalButs = sizeof(procesButs) / sizeof(procesButs[0]);
void setup() {
Serial.begin(115200);
for (int8_t i = 0; i < TotalButs; i++) {
Serial.print(procesButs[i].title);
Serial.println(procesButs[i].toString());
}
}
void loop() {}
//
// Результат
//
// tLeto: 23.5
// tSima: 24.4
// tPod: 45
// vrOpr: 15
// Nasos: Yes
Ну, это можно делать миллионом способов, причем способы сильно отличаются по изящности и требованиям к знанию и пониманию языка. Я покажу Вам один из самых топорных способов, преимущество которого в том, что он требует минимальных изменений Вашего кода.
Суть в том, чтобы помнить какой тип изначально был указан и в любой обработке это учитывать. Я привел пример обработки – преобразование к строке, пример полностью рабочий, можете запускать.
// -------Параметры, выбираемые в меню --------
float tComfSummer = 23.5; // летняя температура комфорта в комнате !!!!!!!!!!!!!!!
float tComfWinter = 24.4; // зимняя температура комфорта в комнате !!!!!!!!!!!!!!
byte tInpStr = 45; // средняя температура подачи теплоносителя
byte timeQuer = 15; // Время опроса датчиков
boolean Pump = 1 ; // контроль циркуляционного насоса 1- вкл, 0 выкл !!!!!!!!!!!!!!
//-----------------------------------------------
enum ParamType { PT_FLOAT, PT_BYTE, PT_BOOL }; // Перечисляем все возможные типы
typedef struct _procesBut {
ParamType pType;
_procesBut(void(*cb)(char), float * p, const char *st) : on_click(cb), param(p), title(st) { pType = PT_FLOAT; }
_procesBut(void(*cb)(char), byte * p, const char *st) : on_click(cb), param(p), title(st) { pType = PT_BYTE; }
_procesBut(void(*cb)(char), bool * p, const char *st) : on_click(cb), param(p), title(st) { pType = PT_BOOL; }
void(*on_click)(char);
void *param; //!!!!!!!!!!!! ВОПРОС ПО ЭТОМУ ПАРАМЕТРУ
String title;
// Для примера - как с этим работать - преобразование к строке
char * toString(void) {
static char sBuffer[7];
static const int8_t buffSize = sizeof(sBuffer) - 1;
switch(pType) {
case PT_FLOAT:
dtostrf(*(float *)param, -buffSize, 1, sBuffer);
break;
case PT_BYTE:
utoa(*(byte *)param, sBuffer, 10);
break;
case PT_BOOL:
strcpy(sBuffer, *(bool *)param ? "Yes" : "No");
break;
}
return sBuffer;
}
} ProcesBut;
void Edit_tPrmComfSummer(char) {}
void Edit_tPrmComfWinter(char) {}
void Edit_tInpStr(char) {}
void SettingPump(char) {}
ProcesBut procesButs[] = {
ProcesBut(Edit_tPrmComfSummer, &tComfSummer, "tLeto: "), // летняя температура комфорта в комнате !!!!!!!!! указал ссылки на перемен
ProcesBut(Edit_tPrmComfWinter, &tComfWinter, "tSima: "), // зимняя температура комфорта в комнате !!!!!!!!! указал ссылки на перемен
ProcesBut(Edit_tInpStr, &tInpStr, "tPod: "), // средняя температура подачи теплоносителя !!!!!!!!! указал ссылки на перемен
ProcesBut(Edit_tInpStr, &timeQuer, "vrOpr: "), // время опроса (задействуем туже функцию что и в темп.подачи)
ProcesBut(SettingPump, &Pump, "Nasos: ") // контроль циркуляционного насоса !!!!!!!!! указал ссылки на перемен
};
static int8_t TotalButs = sizeof(procesButs) / sizeof(procesButs[0]);
void setup() {
Serial.begin(115200);
for (int8_t i = 0; i < TotalButs; i++) {
Serial.print(procesButs[i].title);
Serial.println(procesButs[i].toString());
}
}
void loop() {}
//
// Результат
//
// tLeto: 23.5
// tSima: 24.4
// tPod: 45
// vrOpr: 15
// Nasos: Yes
Огромное спасибо Евгений!!!
Теперь мне нужно осознать это все )) . Я так учусь, никак теория не дается, а когда какие то задачки решаю в виртуальной среде, гораздо быстрее понимание приходит.
Евгений, еще раз спасибо, все работает именно так как мне и хотелось, на дисплей все выводится!!!
Только вот мои познания, как оказалось, совсем мизерные..
Честно говоря, я даже не мог предположить что функции можно внутри структуры создавать? (поправьте если я не правильно выразился), мне бы почитать про строки 23-37, как это в поиске набрать можно? (строки 13-17 это думаю я найду информацию как работать с перечислениями..
Структуры - те же классы, так что содавайте на здоровье.
А про строки 23-37, что именно там вызывает вопросы?
Вопрос, почему этот код находится внутри typedef struct _procesBut {}, это ведь функция и внутри структуры? Я просто таких примеров нигде не встречал на просторах инета и во всяких обучалках, поэтому очень интересно, как это называется, что бы найти или где об этом почитать..
Здравствуйте. Подскажите, если в программе будет постоянно присваиваться переменной некое значение в цикле, может это убить память МК и насколько быстро? В плане надежности что лучше использовать глобальные или локальные переменные для старых atmega 328?
Подскажите, есть какой-нибудь способ разместить массив в памяти ардуино по заданному адресу ?
Есть (ну, при условии, что по заданному адресу есть достаточно свободного места).
Только не спрашивайте как это сделать до тех пор, пока не объясните для чего Вам это надо, посколько я абсолютно уверен, что это Вам не нужно, а задача такая возникла просто из-за непонимания чего-то другого.
b612 пишет:
И чтобы с гарантией, что элементы его будут идти по порядку.
А это только за отдельную плату.
Как-то лично присутствовал при таком диалоге.
Заказчик ведёт переговоры о ТЗ на программный модуль и стоимости работ:
- Так, и ещё Вы должны гарантировать, что выдаваемая величина никогда не превысит единицу, это очень важно, давайте допишем это в ТЗ;
- Но ... эта величина - есть просто косинус обработанной входной величины.
- Да, я знаю, и Вы должны обеспечить, что если она окахется больше единицы, то Ваш модуль выдаст не её саму, а единицу.
- Ну, ... хорошо, но это несколько удорожит работу.
- Если не сильно, скажем не более 5%, то я согласен. Давайте пропишем в ТЗ и поправим стоимость работ.
Так мужик и заплатил лишние 140т.р. за то, чтобы разаработчики гарантировали, что косинус единицу не превысит.
Подскажите, есть какой-нибудь способ разместить массив в памяти ардуино по заданному адресу ?
Есть (ну, при условии, что по заданному адресу есть достаточно свободного места).
Только не спрашивайте как это сделать до тех пор, пока не объясните для чего Вам это надо, посколько я абсолютно уверен, что это Вам не нужно, а задача такая возникла просто из-за непонимания чего-то другого.
я пишу массив в котором находятся пренастройки в EEPROM.
Должна быть возможность заливать эти же настройки из hex-а точнее из файла .eep, сформированного совсем другой программой.
Опять же при перекомпиляции и перепрошивке программы, она должна нормально со старым EEPROM-ом
Так и задавайте структурой. Все настройки объединить в одну структуру и её использовать в обеих программах, чтобы при лбых изменениях структуры, менялось сразу в обеих.
Так и задавайте структурой. Все настройки объединить в одну структуру и её использовать в обеих программах, чтобы при лбых изменениях структуры, менялось сразу в обеих.
Понятно, но эти массивы принадлежат совершенно разным частям программы и программы пишут разные люди и в разное время, вообщем там трудно договориться.
Проще было бы задать адреса железно.
Может быть объявить всю память одним массивом а потом просто определить указатели, но тогда тоже проблемы.
При рошивке одного массива будет наверно затираться вся память.
Вы явно не понимаете сути макроса EMEM - смысл его именно в том, что адреса размещения данных в ЕЕПРОМ выбираются автоматически. Так что Ваш вопрос "Как задать адреса для EMEM?" совершенно бессмысленный и ответ только один - никак.
Если вам нужно размещать данные по конкретным адресам - работайте с eeprom_read_byte()
Вы явно не понимаете сути макроса EMEM - смысл его именно в том, что адреса размещения данных в ЕЕПРОМ выбираются автоматически. Так что Ваш вопрос "Как задать адреса для EMEM?" совершенно бессмысленный и ответ только один - никак.
Если вам нужно размещать данные по конкретным адресам - работайте с eeprom_read_byte()
возможно.
ноги начали расти из того, что надо было както разместить данные в еепроме, не тратя на это флэш.
А раз получилось разместить массивы при помощи EMEMа, то хотелось бы чтобы они размещались не где им вздумается
А раз получилось разместить массивы при помощи EMEMа, то хотелось бы чтобы они размещались не где им вздумается
А можете пояснить, зачем нужно писать массивы по фиксированным адресам? - мне вот опять кажется, что вы с сутью макроса ЕМЕМ не разобрались... Этот метод размещения данных в ЕЕПРОМ не требует знания адресов - ни для записи, ни для считывания.
Вы когда создаете массив в оперативке, например
int foo[32]
вас же не интересует, по какому адресу он создался? - вы вообще не работает с адресами, вы обращаетесь к массиву по имени. Ну и в случае EEMEM все ровно так же
И это тоже константа, но без всяких const и #define. Простенько и если надо можно на месте поменять.
если в loop() ничо не вставлять, вызывается он примерно 50 тысяч раз в секунду.
Да, нет, гораздо больше - 1,136МГц.
И это тоже константа, но без всяких const и #define. Простенько и если надо можно на месте поменять.
Все так спорно... так спорно... Нахрена константу "МЕНЯТЬ НА МЕСТЕ" (!!!) это же константа !!!!!!!
const и правда спецификатор, это не откровение, имхо, ни для кого :)
Компилятор ничего не решает, он разместит ее в озу :)
И на десерт, понятие константа означает - постоянный, неизменный :)
И кстати...
Cl_AAA AAA(
/*константа*/
12); - что это за бред?
const и правда спецификатор, это не откровение, имхо, ни для кого :)
Компилятор ничего не решает, он разместит ее в озу :)
И на десерт, понятие константа означает - постоянный, неизменный :)
И кстати...
Cl_AAA AAA(
/*константа*/
12); - что это за бред?
Что спорно? В языке Си нет инструмента объявления только для образования констант. Или пользоваться макросом, или спецификатором const. Но и то и другое объявляет не только константы.
ПС:http://ci-plus-plus-snachala.ru/?p=1120
Сами-то поняли что сказали?
а - формальный параметр, снаружи она не существует, а потому никак не может быть ни переменной, ни чем бы то ни было ещё.
В этом вашем лживом С++ никада нельзя сказать точно, что сегодня с утра означает оператор присваивания. А вы тут про медленно меняющиеся константы....
Я, када встретил в одном коде #define FALSE TRUE, две недели пилъ беспробудно.
Зато туева хуча человеков стандарты выдумывает, уже Х томов понаписали. Мне эта ситуация почему-то напоминает поговорку "У семи нянек - дитя без глазу". Только тут икспердов-нянек гораздо больше чем семь, поэтому дитя у них, не успеешь отвернуца, не то что без глазика, а вапще валяется покрошенное в фарш.
В этом вашем лживом С++ никада нельзя сказать точно, что сегодня с утра означает оператор присваивания.
Это ещё ничо. Ессть языки, где вся эта хрень может изменяться по ходу выполнения программы.
и что вы тут поменяли на лету и что такое "/*пин A*/2" и далее
Это ещё ничо. Ессть языки, где вся эта хрень может изменяться по ходу выполнения программы.
я не спец, но ни одного языка высокого уровня окромя убогово javascript я не видел возможность изменения предопределенной константы. Есть только в C++ (за C не скажу) и производных возможность снять признак постоянства. Но обычно в жизни считается подобное мерой крайней и не культурной. Хотя сам по себе язык такое позволяет.
А ну и конечно случаи не корректной передачи данных внутрь вызываемых функций (когда передают как сами данные, так и казатель на них, а внутри рабоитают, если грубо, то с обратной стороны).
компилятор просто не даст этого
Чего не даст? Константу поменять? А кто его спрашивать-то будет? :)
убогово javascript
Фига се! Это про язык с динамическим полиморфизмом и прототипным наследованием? Боюсь, что использованное Вами прилагательное больше отражает уровень Ваших знаий о JavaScript, чем природу языка.
я не видел возможность изменения предопределенной константы.
В старом добром Фортране IV это была штатаная фича. Причём менялась константа как таковая (например 5 становилось равным 3 или там 10). И, повторяю, это была не особенность реализации, а штатная фича. В таком виде Фортран существовал десятилетиями. Ушло это только в новых стандартах, причём обычно есть опция "вернуть" для совместимости с миллиардами строк кода, написанных на Фортране.
в жизни считается подобное мерой крайней и не культурной.
Я бы сказал "говнокодом".
Вообще, изначально в своей реплике я противопоставил #define - const, говоря о том, что такой прием, часто позволяет съэкономить оперативку, а иногда ускориться, и уже как на побочку намекнул на некую нестыковку самого определения константы и возможных с ней операций :) Естественно все это в приложении к ардуино.
В этом вашем лживом С++ никада нельзя сказать точно, что сегодня с утра означает оператор присваивания. А вы тут про медленно меняющиеся константы....
Я, када встретил в одном коде #define FALSE TRUE, две недели пилъ беспробудно.
Зато туева хуча человеков стандарты выдумывает, уже Х томов понаписали. Мне эта ситуация почему-то напоминает поговорку "У семи нянек - дитя без глазу". Только тут икспердов-нянек гораздо больше чем семь, поэтому дитя у них, не успеешь отвернуца, не то что без глазика, а вапще валяется покрошенное в фарш.
Мелочи. Уже приводил тут примерчик из реального и не мелкого проекта, что-то типа так:
Вот это - точно засада..
Вот это - точно засада..
Ну, почему сразу засада. Если по жизни стояла задача: "Если p, то с вероятностью 0,1 выполнить ...", то конструкция как конструкция. Прокомментировать как следует и, когда станет не нужна, выбросить #undef'ом. Хотя, я бы делал это по-другому.
Привет. Вопросик.
Есть переменная
double tm = 0 ;
в цикле loop ей присвоили значение в минутах работы системы
tm = ((millis()/1000)/60);
Пытаетесь программировать на языке, которого не знаете и знать не хотите (ни одна нормальная книжка по языку Вами не прочитана).
Целочисленное деление в этом языке производится с отбрасванием остатка, каким бы он ни был. Результат всегда целый. Например, 200/200 и 300/200 и 399/200 - результат один и тот же, а именно - 1.
А как узнать размер стека в настоящий момент?
А как узнать размер стека в настоящий момент?
Указатель стека называется SP. Он доступен в любой момент. Т.е. запомните его в началеа потом посмотрите в нужной точке и, вычтя одно из другого, узнаете какой стек Вы уже накопили.
В принципе, вот в этой теме, в конце первого поста, есть программа Memory Explorer. Она печатает и стек, и кучу, и свободные куски.
Всем привет!
А что вы обычно делаете когда внезапно : Sketch uses ... (95%) of program storage space.
В проекте пара десятков .cpp & .h файлов, все внешние библиотеки отключил, где можно поставил пустые заглушки.
Но без внешних библиотек стало не сильно лучше ~50%, интересно как посмотреть какой именно свой модуль жрет flash?
Вы дали слишком мало информации, чтобы можно было ответить конкретно. Но, в целом, если Вы не понимаете какой модуль отжирает, попробуйте
1. Назначить свой фолдер build
2. После компиляции посмотрите в него и во все его подфолдеры. Там будут файлы с названиями Ваших модулей (и библиотечных, и системных тоже) с расширением ".o" - это скомпилированные файлы модулей.
Вот и смотрите какой из них какого размера. Это не точно, но общее представление даст.
У меня работает программа со 100% storage space. Специально менял порядок операторов, что бы уложить последние 2 байта. Никаких проблем.
Спасибо! тут всё просто : Sketch uses ... (91%) of program storage space. вот и вся информация.
Ее уже достаточно что-бы задуматься.
В папочке \arduino_bulid_xxxxx\ всем-известные библиотеки Wire, SPI, RadioHead
Гораздо интереснее в папке \core
Там откуда-то взялись HardwareSerial.cpp.*, USBCore.cpp.* и IPAddress.cpp.*
100% нигде у меня они не подключены, и не могут быть подключены, интересно, где посмотреть кто их за собой тянет?
Откомпилируйте вот такую программу
а потом посмотрите в ту самую папку.
уже компилировал пустой проект, и обалдел от объёма .o & .d файлов.
с другой стороны, всё это изобилие занимает 450 bytes (1%) of program storage space.
что подтверждает мои подозрения, что по объёму .o & .d файлов в build/libraries ничего определенного сказать не получится
Не получится - это даст только общее предствление.
Дело в том, что линкер безжалостно выбросит всё, что не испольузется.
Вы представляете себе работу компилятора и линкера? Те, кто представляют, те никогда не ленятся лишний раз написать слово static, например.
Как раз static-ом надо пользоваться осторожно и только по-необходимости. Вы наверное опечатались в слове const.
Нет, я написал то, что хотел написать.
Посмотрите на скетчи, опубликованные здесь на форуме. Если Вы где-то найдёте глобальную переменную или функцию, объявленную как static - это большая редкость. Между тем, если переменная или функция не вызываются из других файлов, нет никаких причин не объявить их статическими, ну вообще никаких. Люди этого не делают просто из лени, а большинство из непонимания возможных выгод от этого.
Но ведь под статические переменные память резервируется сразу и нет возможности использовать "временно неиспользуемую" память под сиюминутную нужду (большой буфер необходимо сформировать, например). Или таки это плюс, а не минус?
Вы невнимательно читаете, я говорю о глобальных переменных и функциях а под них память тоже занимается сразу и никогда освобождается.
Последнее использование
static
— глобальная переменная в файле кода. В этом случае использованиеstatic
указывает, что исходный код в других файлах, которые являются частью проекта, не может получить доступ к переменной. Только код внутри того же файла может увидеть переменную (её область видимости ограничена файлом). Эта техника может быть использована для моделирования объектно-ориентированного кода, потому что она ограничивает видимость переменных и таким образом помогает избежать конфликта имен. Этот способ использованияstatic
является пережитком Cи.А, ну теперь понятно. Я столько глобалов не создаю, чтобы прям запутаться в них (вообще редко создаю), поэтому статик только для сохранения значений внутри функции использовал (и подумал, что лажаю с ним, если не ставлю везде )). Ну и... паттернализм, вобщем - что всегда делаем, о том постоянно и думаем.
Совершенно верно.
И это даёт оптимизатору право смело выбрасывать переменную (или переводить её в регистр, а то и в непосредственное значение), если в этом файле она не нужна, т.к. из других файлов она не доступна.
А вот если она не статик, то компилятор не может её выбросить, т.к. вдруг она из другого файла используется? В этом случае её может выбросить только линкер.
Ну, а поскольку алгоритмы оптимизаторов сложны и порой непредсказуемы, два шанса выбросить - лучше, чем один.
Т.е. объявляя её static, мы помогаем оптимизатору.
Тоже касается и функций. Если функция глобальна и Вы не планируете использовать её из других файлов - не скрывайте этого от оптимизатора - объявите static. Он её может в inline засунет или, если Вы перестали её использовать, запросто вообще выбросит.
Большинство моих классов полностью статические, т.е. все поля и методы у них объявлены как static, всё что static const и более-менее крупное - объявлено как PROGMEM. Никаких #define для констант - только static const с контролем типов.
>Почему преимущественно статические классы ?
<А для того чтобы не создавать экземпляров, у меня на плате только один LCD-экран, одни RTC-часы и т.д. зачем мне дурацкие конструкторы, передающие номера пинов, запоминающие эти пины в оперативке(а именно так и происходит в большинстве библиотек), -хотя вся конфигурация известна на момент компиляции.
Но, бездумно тыкая везде static я забыл что элементы-то меню у меня динамически создаются и тут я профукал 78 байт оперативки на ровном месте, а таких мест десятки.
...
p.s. а размеры функций можно посмотреть утилитой av-nm ( https://blog.benoitblanchon.fr/arduino-code-size-and-assembly/ ) просто обалденная штука, сортирует функции по величине и корректно отображает названия, очень рекомендую.
Здравствуйте.
Делаю менюшку в одном варианте все получилось (но там все переменные должны быть одинакового типа), не очень удобно, а во втором варианте, не получается получить (и вывести) значение параметра. Можете подсказать синтаксис и вообще, может через неопределенный тип это опасно делать?
Ну, это можно делать миллионом способов, причем способы сильно отличаются по изящности и требованиям к знанию и пониманию языка. Я покажу Вам один из самых топорных способов, преимущество которого в том, что он требует минимальных изменений Вашего кода.
Суть в том, чтобы помнить какой тип изначально был указан и в любой обработке это учитывать. Я привел пример обработки – преобразование к строке, пример полностью рабочий, можете запускать.
Ну, это можно делать миллионом способов, причем способы сильно отличаются по изящности и требованиям к знанию и пониманию языка. Я покажу Вам один из самых топорных способов, преимущество которого в том, что он требует минимальных изменений Вашего кода.
Суть в том, чтобы помнить какой тип изначально был указан и в любой обработке это учитывать. Я привел пример обработки – преобразование к строке, пример полностью рабочий, можете запускать.
Огромное спасибо Евгений!!!
Теперь мне нужно осознать это все )) . Я так учусь, никак теория не дается, а когда какие то задачки решаю в виртуальной среде, гораздо быстрее понимание приходит.
Евгений, еще раз спасибо, все работает именно так как мне и хотелось, на дисплей все выводится!!!
Только вот мои познания, как оказалось, совсем мизерные..
Честно говоря, я даже не мог предположить что функции можно внутри структуры создавать? (поправьте если я не правильно выразился), мне бы почитать про строки 23-37, как это в поиске набрать можно? (строки 13-17 это думаю я найду информацию как работать с перечислениями..
Структуры - те же классы, так что содавайте на здоровье.
А про строки 23-37, что именно там вызывает вопросы?
Структуры - те же классы, так что содавайте на здоровье.
А про строки 23-37, что именно там вызывает вопросы?
Вопрос, почему этот код находится внутри typedef struct _procesBut {}, это ведь функция и внутри структуры? Я просто таких примеров нигде не встречал на просторах инета и во всяких обучалках, поэтому очень интересно, как это называется, что бы найти или где об этом почитать..
Почитайте про классы - там таких примеров навалом. А структура - тот же класс, разница невелика от слова совсем.
Почитайте про классы - там таких примеров навалом. А структура - тот же класс, разница невелика от слова совсем.
Понял! Спасибо огромное за помощ!!! Доволен как слон ))). Два дня поисков и головоломок... сам бы я не разобрался...
Здравствуйте. Подскажите, если в программе будет постоянно присваиваться переменной некое значение в цикле, может это убить память МК и насколько быстро? В плане надежности что лучше использовать глобальные или локальные переменные для старых atmega 328?
если кратко, то: 1. нет, не может. 2. глобальных переменных лучше избегать
Подскажите, есть какой-нибудь способ разместить массив в памяти ардуино по заданному адресу ?
И чтобы с гарантией, что элементы его будут идти по порядку.
Подскажите, есть какой-нибудь способ разместить массив в памяти ардуино по заданному адресу ?
Есть (ну, при условии, что по заданному адресу есть достаточно свободного места).
Только не спрашивайте как это сделать до тех пор, пока не объясните для чего Вам это надо, посколько я абсолютно уверен, что это Вам не нужно, а задача такая возникла просто из-за непонимания чего-то другого.
И чтобы с гарантией, что элементы его будут идти по порядку.
А это только за отдельную плату.
Как-то лично присутствовал при таком диалоге.
Заказчик ведёт переговоры о ТЗ на программный модуль и стоимости работ:
- Так, и ещё Вы должны гарантировать, что выдаваемая величина никогда не превысит единицу, это очень важно, давайте допишем это в ТЗ;
- Но ... эта величина - есть просто косинус обработанной входной величины.
- Да, я знаю, и Вы должны обеспечить, что если она окахется больше единицы, то Ваш модуль выдаст не её саму, а единицу.
- Ну, ... хорошо, но это несколько удорожит работу.
- Если не сильно, скажем не более 5%, то я согласен. Давайте пропишем в ТЗ и поправим стоимость работ.
Так мужик и заплатил лишние 140т.р. за то, чтобы разаработчики гарантировали, что косинус единицу не превысит.
У Вас тут примерно также.
Подскажите, есть какой-нибудь способ разместить массив в памяти ардуино по заданному адресу ?
Есть (ну, при условии, что по заданному адресу есть достаточно свободного места).
Только не спрашивайте как это сделать до тех пор, пока не объясните для чего Вам это надо, посколько я абсолютно уверен, что это Вам не нужно, а задача такая возникла просто из-за непонимания чего-то другого.
Должна быть возможность заливать эти же настройки из hex-а точнее из файла .eep, сформированного совсем другой программой.
Опять же при перекомпиляции и перепрошивке программы, она должна нормально со старым EEPROM-ом
Т.е. я должен чётко задать где что будет лежать.
Так и задавайте структурой. Все настройки объединить в одну структуру и её использовать в обеих программах, чтобы при лбых изменениях структуры, менялось сразу в обеих.
Так и задавайте структурой. Все настройки объединить в одну структуру и её использовать в обеих программах, чтобы при лбых изменениях структуры, менялось сразу в обеих.
Проще было бы задать адреса железно.
Может быть объявить всю память одним массивом а потом просто определить указатели, но тогда тоже проблемы.
При рошивке одного массива будет наверно затираться вся память.
Вообщем придётся возвращаться к EEPROM.read(...
Вообщем придётся возвращаться к EEPROM.read(...
Вы явно не понимаете сути макроса EMEM - смысл его именно в том, что адреса размещения данных в ЕЕПРОМ выбираются автоматически. Так что Ваш вопрос "Как задать адреса для EMEM?" совершенно бессмысленный и ответ только один - никак.
Если вам нужно размещать данные по конкретным адресам - работайте с eeprom_read_byte()
Вы явно не понимаете сути макроса EMEM - смысл его именно в том, что адреса размещения данных в ЕЕПРОМ выбираются автоматически. Так что Ваш вопрос "Как задать адреса для EMEM?" совершенно бессмысленный и ответ только один - никак.
Если вам нужно размещать данные по конкретным адресам - работайте с eeprom_read_byte()
ноги начали расти из того, что надо было както разместить данные в еепроме, не тратя на это флэш.
А раз получилось разместить массивы при помощи EMEMа, то хотелось бы чтобы они размещались не где им вздумается
ноги начали расти из того, что надо было както разместить данные в еепроме, не тратя на это флэш.
ну, чудес-то не бывает - чтобы использовать ваши данные, что хранятся в EMEM - вы все равно сначала их в оперативку считываете
А раз получилось разместить массивы при помощи EMEMа, то хотелось бы чтобы они размещались не где им вздумается
А можете пояснить, зачем нужно писать массивы по фиксированным адресам? - мне вот опять кажется, что вы с сутью макроса ЕМЕМ не разобрались... Этот метод размещения данных в ЕЕПРОМ не требует знания адресов - ни для записи, ни для считывания.
Вы когда создаете массив в оперативке, например
int foo[32]
вас же не интересует, по какому адресу он создался? - вы вообще не работает с адресами, вы обращаетесь к массиву по имени. Ну и в случае EEMEM все ровно так же