Этюды для начинающих: Память 1. Что и как не надо делать

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

brokly пишет:
Кстати, я почему то не нашел объяснения для чего нужны константы. Коллизия, объявлена как константа а храниться в ОЗУ. Хотя можем принудительно пихнуть ее во флешь, но тогда работать с ней придется с подвывертом (понимая, что это и почему).
Прежде всего const это спецификатор. И он сообщает что данная величина используется только для чтения. А уже потом компилятор решает как компактно и эфеективно ее разместить. Из этого не следует что const это обязательно константа.  Так же #define не делает что-то константой .  И вот еще мой вариант который мне больше нравится 

Cl_AAA AAA(/*константа*/12);

И это тоже константа, но без всяких const  и #define. Простенько и если надо можно на месте поменять.

const byte pin=/*пин A*/2;
#define pin1  /*пин B*/3

 

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

DetSimen пишет:

если в loop() ничо не вставлять, вызывается он примерно 50 тысяч раз в секунду. 

Да, нет, гораздо больше - 1,136МГц.

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

qwone пишет:

brokly пишет:
Кстати, я почему то не нашел объяснения для чего нужны константы. Коллизия, объявлена как константа а храниться в ОЗУ. Хотя можем принудительно пихнуть ее во флешь, но тогда работать с ней придется с подвывертом (понимая, что это и почему).
Прежде всего const это спецификатор. И он сообщает что данная величина используется только для чтения. А уже потом компилятор решает как компактно и эфеективно ее разместить. Из этого не следует что const это обязательно константа.  Так же #define не делает что-то константой .  И вот еще мой вариант который мне больше нравится 

Cl_AAA AAA(/*константа*/12);

И это тоже константа, но без всяких const  и #define. Простенько и если надо можно на месте поменять.

const byte pin=/*пин A*/2;
#define pin1  /*пин B*/3

 

 

Все так спорно... так спорно... Нахрена константу "МЕНЯТЬ НА МЕСТЕ" (!!!) это же константа !!!!!!!

const и правда спецификатор, это не откровение, имхо, ни для кого :)

Компилятор ничего не решает, он разместит ее в озу :) 

И на десерт, понятие константа означает - постоянный, неизменный :)

И кстати... Cl_AAA AAA(/*константа*/12); - что это за бред?

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

brokly пишет:
Все так спорно... так спорно... Нахрена константу "МЕНЯТЬ НА МЕСТЕ" (!!!) это же константа !!!!!!!

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 байт.
*/

ПС:http://ci-plus-plus-snachala.ru/?p=1120

/**/
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 байт.
*/

 

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

qwone пишет:

/**/
void func (const int a) { // <- a должна быть константой
  /*но только внутри функции,а снаружи это переменная*/
 

Сами-то поняли что сказали?

а - формальный параметр, снаружи она не существует, а потому никак не может быть ни переменной, ни чем бы то ни было ещё.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

В этом вашем лживом С++ никада нельзя сказать точно, что сегодня с утра означает оператор присваивания. А вы тут про медленно меняющиеся константы.... 

Я, када встретил в одном коде #define FALSE TRUE,  две недели пилъ беспробудно. 

Зато туева хуча человеков стандарты выдумывает, уже Х томов понаписали.  Мне эта ситуация почему-то напоминает поговорку "У семи нянек - дитя без глазу". Только тут икспердов-нянек гораздо больше чем семь, поэтому дитя у них, не успеешь отвернуца, не то что без глазика, а вапще валяется покрошенное в фарш. 

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

DetSimen пишет:

В этом вашем лживом С++ никада нельзя сказать точно, что сегодня с утра означает оператор присваивания. 

Это ещё ничо. Ессть языки, где вся эта хрень может изменяться по ходу выполнения программы.

sirota
Offline
Зарегистрирован: 18.08.2015

qwone пишет:

 

const byte pin=/*пин A*/2;
#define pin1  /*пин B*/3

 

 

и что вы тут поменяли на лету и что такое "/*пин A*/2" и далее

ЕвгенийП пишет:

Это ещё ничо. Ессть языки, где вся эта хрень может изменяться по ходу выполнения программы.

я не спец, но ни одного языка высокого уровня окромя убогово javascript  я не видел возможность изменения предопределенной константы. Есть только в C++ (за C не скажу) и производных возможность снять признак постоянства. Но обычно в жизни считается подобное мерой крайней и не культурной. Хотя сам по себе язык такое позволяет.

А ну и конечно случаи не корректной передачи данных внутрь вызываемых функций (когда передают как сами данные, так и казатель на них, а внутри рабоитают, если грубо, то с обратной стороны).

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

sirota пишет:

компилятор просто не даст этого

Чего не даст? Константу поменять? А кто его спрашивать-то будет? :)

sirota пишет:

убогово javascript

Фига се! Это про язык с динамическим полиморфизмом и прототипным наследованием? Боюсь, что использованное Вами прилагательное больше отражает уровень Ваших знаий о JavaScript, чем природу языка.

sirota пишет:

я не видел возможность изменения предопределенной константы.

В старом добром Фортране IV это была штатаная фича. Причём менялась константа как таковая (например 5 становилось равным 3 или там 10). И, повторяю, это была не особенность реализации, а штатная фича. В таком виде Фортран существовал десятилетиями. Ушло это только в новых стандартах, причём обычно есть опция "вернуть" для совместимости с миллиардами строк кода, написанных на Фортране.

sirota пишет:

 в жизни считается подобное мерой крайней и не культурной. 

Я бы сказал "говнокодом".

 

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

Вообще, изначально в своей реплике я противопоставил #define - const, говоря о том, что такой прием, часто позволяет съэкономить оперативку, а иногда ускориться, и уже как на побочку намекнул на некую нестыковку самого определения константы и возможных с ней операций :) Естественно все это в приложении к ардуино.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

DetSimen пишет:

В этом вашем лживом С++ никада нельзя сказать точно, что сегодня с утра означает оператор присваивания. А вы тут про медленно меняющиеся константы.... 

Я, када встретил в одном коде #define FALSE TRUE,  две недели пилъ беспробудно. 

Зато туева хуча человеков стандарты выдумывает, уже Х томов понаписали.  Мне эта ситуация почему-то напоминает поговорку "У семи нянек - дитя без глазу". Только тут икспердов-нянек гораздо больше чем семь, поэтому дитя у них, не успеешь отвернуца, не то что без глазика, а вапще валяется покрошенное в фарш. 

Мелочи. Уже приводил тут примерчик из реального и не мелкого проекта, что-то типа так:

#if !defined( _MY_CONST_ )
#define if(p) if( (rand()%100>10) && (p) )
#endif

Вот это - точно засада..

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

Arhat109-2 пишет:

Вот это - точно засада..

Ну, почему сразу засада. Если по жизни стояла задача: "Если p, то с вероятностью 0,1 выполнить ...", то конструкция как конструкция. Прокомментировать как следует и, когда станет не нужна, выбросить #undef'ом. Хотя, я бы делал это по-другому.

pridecom
Offline
Зарегистрирован: 07.07.2017

Привет. Вопросик.

Есть переменная 

double tm = 0 ;

в цикле loop ей присвоили значение в минутах работы системы

tm = ((millis()/1000)/60);

и выводим на экран.
lcd.print(tm ); 
 
Например 
110000 милисек это 110 сек или 1.83 минуты
Однако выводит почему-то 1.00 минуты, округляет обрезая до нулей гадина
что я делаю не так?
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

pridecom пишет:

что я делаю не так?

Пытаетесь программировать на языке, которого не знаете и знать не хотите (ни одна нормальная книжка по языку Вами не прочитана).

Целочисленное деление в этом языке производится с отбрасванием остатка, каким бы он ни был. Результат всегда целый. Например, 200/200 и 300/200 и 399/200 - результат один и тот же, а именно - 1.

pmaster
Offline
Зарегистрирован: 23.05.2011

А как узнать размер стека в настоящий момент? 

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

pmaster пишет:

А как узнать размер стека в настоящий момент? 

Указатель стека называется SP. Он доступен в любой момент. Т.е. запомните его в началеа потом посмотрите в нужной точке и, вычтя одно из другого, узнаете какой стек Вы уже накопили.

В принципе, вот в этой теме, в конце первого поста, есть программа Memory Explorer. Она печатает и стек, и кучу, и свободные куски.

kokuam
kokuam аватар
Offline
Зарегистрирован: 10.01.2017

Всем привет!

А что вы обычно делаете когда внезапно : Sketch uses ... (95%) of program storage space.

В проекте пара десятков .cpp & .h файлов, все внешние библиотеки отключил, где можно поставил пустые заглушки.

Но без внешних библиотек стало не сильно лучше ~50%, интересно как посмотреть какой именно свой модуль жрет flash? 

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

Вы дали слишком мало информации, чтобы можно было ответить конкретно. Но, в целом, если Вы не понимаете какой модуль отжирает, попробуйте

1. Назначить свой фолдер build
2. После компиляции посмотрите в него и во все его подфолдеры. Там будут файлы с названиями Ваших модулей (и библиотечных, и системных тоже) с расширением ".o" - это скомпилированные файлы модулей.

Вот и смотрите какой из них какого размера. Это не точно, но общее представление даст.

nik182
Offline
Зарегистрирован: 04.05.2015

У меня работает программа со 100% storage space. Специально менял порядок операторов, что бы уложить последние 2 байта. Никаких проблем.

kokuam
kokuam аватар
Offline
Зарегистрирован: 10.01.2017

Спасибо! тут всё просто : Sketch uses ... (91%) of program storage space. вот и вся информация.
Ее уже достаточно что-бы задуматься. 

В папочке \arduino_bulid_xxxxx\  всем-известные библиотеки  Wire,  SPI, RadioHead
Гораздо интереснее в папке \core
Там откуда-то взялись HardwareSerial.cpp.*, USBCore.cpp.* и IPAddress.cpp.*
100% нигде у меня они не подключены, и не могут быть подключены, интересно, где посмотреть кто их за собой тянет?

 

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

Откомпилируйте вот такую программу

void setup(void) {}
void loop(void) {}

а потом посмотрите в ту самую папку.

kokuam
kokuam аватар
Offline
Зарегистрирован: 10.01.2017

уже компилировал пустой проект, и обалдел от объёма  .o & .d файлов.

с другой стороны, всё это изобилие занимает 450 bytes (1%) of program storage space.

что подтверждает мои подозрения, что по объёму .o & .d файлов в build/libraries ничего определенного сказать не получится

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

Не получится - это даст только общее предствление.

Дело в том, что линкер безжалостно выбросит всё, что не испольузется.

Вы представляете себе работу компилятора и линкера? Те, кто представляют, те никогда не ленятся лишний раз написать слово static, например.

kokuam
kokuam аватар
Offline
Зарегистрирован: 10.01.2017

Как раз static-ом надо пользоваться осторожно и только по-необходимости. Вы наверное опечатались в слове const.

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

Нет, я написал то, что хотел написать. 

Посмотрите на скетчи, опубликованные здесь на форуме. Если Вы где-то найдёте глобальную переменную или функцию, объявленную как static - это большая редкость. Между тем, если переменная или функция не вызываются из других файлов, нет никаких причин не объявить их статическими, ну вообще никаких. Люди этого не делают просто из лени, а большинство из непонимания возможных выгод от этого.

sadman41
Offline
Зарегистрирован: 19.10.2016

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

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

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

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

Последнее использование static— глобальная переменная в файле кода. В этом случае использование staticуказывает, что исходный код в других файлах, которые являются частью проекта, не может получить доступ к переменной. Только код внутри того же файла может увидеть переменную (её область видимости ограничена файлом). Эта техника может быть использована для моделирования объектно-ориентированного кода, потому что она ограничивает видимость переменных и таким образом помогает избежать конфликта имен. Этот способ использования staticявляется пережитком Cи.

Женя про это написал.
sadman41
Offline
Зарегистрирован: 19.10.2016

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

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

Совершенно верно.

И это даёт оптимизатору право смело выбрасывать переменную (или переводить её в регистр, а то и в непосредственное значение), если в этом файле она не нужна, т.к. из других файлов она не доступна.

А вот если она не статик, то компилятор не может её выбросить, т.к. вдруг она из другого файла используется? В этом случае её может выбросить только линкер.

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

Т.е. объявляя её static, мы помогаем оптимизатору.

Тоже касается и функций. Если функция глобальна и Вы не планируете использовать её из других файлов - не скрывайте этого от оптимизатора - объявите static. Он её может в inline засунет или, если Вы перестали её использовать, запросто вообще выбросит.

kokuam
kokuam аватар
Offline
Зарегистрирован: 10.01.2017

Большинство моих классов полностью статические, т.е. все поля и методы у них объявлены как static, всё что static const и более-менее крупное - объявлено как PROGMEM. Никаких #define для констант - только static const с контролем типов.

>Почему преимущественно статические классы ?
<А для того чтобы не создавать экземпляров, у меня на плате только один LCD-экран, одни RTC-часы и т.д. зачем мне дурацкие конструкторы, передающие номера пинов, запоминающие эти пины в оперативке(а именно так и происходит в большинстве библиотек), -хотя вся конфигурация известна на момент компиляции.

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

class RangeTranceive : public State {
     ...
     static char scr[screenSize][rowSize]; 
     ...
 }; 

p.s. а размеры функций можно посмотреть утилитой av-nm ( https://blog.benoitblanchon.fr/arduino-code-size-and-assembly/ ) просто обалденная штука, сортирует функции по величине и корректно отображает названия, очень рекомендую.

fil71
Offline
Зарегистрирован: 26.10.2018

Здравствуйте. 

Делаю менюшку в одном варианте все получилось (но там все переменные должны быть одинакового типа), не очень удобно, а во втором варианте, не получается получить (и вывести) значение параметра. Можете подсказать синтаксис и вообще, может через неопределенный тип это опасно делать? 

// -------Параметры, выбираемые в меню  --------
   
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   ???   

 

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

Ну, это можно делать миллионом способов, причем способы сильно отличаются по изящности и требованиям к знанию и пониманию языка. Я покажу Вам один из самых топорных способов, преимущество которого в том, что он требует минимальных изменений Вашего кода.

Суть в том, чтобы помнить какой тип изначально был указан и в любой обработке это учитывать. Я привел пример обработки – преобразование к строке, пример полностью рабочий, можете запускать.

// -------Параметры, выбираемые в меню  --------
   
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

 

fil71
Offline
Зарегистрирован: 26.10.2018

ЕвгенийП пишет:

Ну, это можно делать миллионом способов, причем способы сильно отличаются по изящности и требованиям к знанию и пониманию языка. Я покажу Вам один из самых топорных способов, преимущество которого в том, что он требует минимальных изменений Вашего кода.

Суть в том, чтобы помнить какой тип изначально был указан и в любой обработке это учитывать. Я привел пример обработки – преобразование к строке, пример полностью рабочий, можете запускать.

// -------Параметры, выбираемые в меню  --------
   
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

 

 

Огромное спасибо Евгений!!!

Теперь мне нужно осознать это все )) . Я так учусь, никак теория не дается, а когда какие то задачки решаю в виртуальной среде, гораздо быстрее понимание приходит.

fil71
Offline
Зарегистрирован: 26.10.2018

Евгений, еще раз спасибо, все работает именно так как мне и хотелось, на дисплей все выводится!!! 

Только вот мои познания,  как оказалось, совсем мизерные.. 

Честно говоря, я даже не мог предположить что функции можно внутри структуры создавать? (поправьте если я не правильно выразился), мне бы почитать про строки 23-37, как это в поиске набрать можно?  (строки 13-17 это думаю я найду информацию как работать с  перечислениями..

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

Структуры - те же классы, так что содавайте на здоровье.

А про строки 23-37, что именно там вызывает вопросы?

fil71
Offline
Зарегистрирован: 26.10.2018

ЕвгенийП пишет:

Структуры - те же классы, так что содавайте на здоровье.

А про строки 23-37, что именно там вызывает вопросы?

Вопрос, почему этот код находится внутри typedef struct _procesBut {},  это ведь функция и внутри структуры? Я просто таких примеров нигде не встречал на просторах инета и во всяких обучалках, поэтому очень интересно, как это называется, что бы найти или где об этом почитать.. 

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

Почитайте про классы - там таких примеров навалом. А структура - тот же класс, разница невелика от слова совсем.

fil71
Offline
Зарегистрирован: 26.10.2018

ЕвгенийП пишет:

Почитайте про классы - там таких примеров навалом. А структура - тот же класс, разница невелика от слова совсем.

Понял! Спасибо огромное за помощ!!! Доволен как слон ))).  Два дня поисков и головоломок... сам бы я не разобрался...

Densl
Offline
Зарегистрирован: 28.11.2018

Здравствуйте. Подскажите, если в программе будет постоянно присваиваться переменной некое значение в цикле, может это убить память МК и насколько быстро? В плане надежности что лучше использовать глобальные или локальные переменные для старых atmega 328?

kokuam
kokuam аватар
Offline
Зарегистрирован: 10.01.2017

если кратко, то: 1. нет, не может. 2. глобальных переменных лучше избегать 

b612
Offline
Зарегистрирован: 12.03.2017

Подскажите, есть какой-нибудь способ разместить массив в памяти ардуино по заданному адресу ?

И чтобы с гарантией, что элементы его будут идти по порядку.

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

b612 пишет:

Подскажите, есть какой-нибудь способ разместить массив в памяти ардуино по заданному адресу ?

Есть (ну, при условии, что по заданному адресу есть достаточно свободного места).

Только не спрашивайте как это сделать до тех пор, пока не объясните для чего Вам это надо, посколько я абсолютно уверен, что это Вам не нужно, а задача такая возникла просто из-за непонимания чего-то другого.

b612 пишет:

И чтобы с гарантией, что элементы его будут идти по порядку.

А это только за отдельную плату.

Как-то лично присутствовал при таком диалоге.

Заказчик ведёт переговоры о ТЗ на программный модуль и стоимости работ:

- Так, и ещё Вы должны гарантировать, что выдаваемая величина никогда не превысит единицу, это очень важно, давайте допишем это в ТЗ;
- Но ... эта величина - есть просто косинус обработанной входной величины.
- Да, я знаю, и Вы должны обеспечить, что если она окахется больше единицы, то Ваш модуль выдаст не её саму, а единицу.
- Ну, ... хорошо, но это несколько удорожит работу.
- Если не сильно, скажем не более 5%, то я согласен. Давайте пропишем в ТЗ и поправим стоимость работ.

Так мужик и заплатил лишние 140т.р. за то, чтобы разаработчики гарантировали, что косинус единицу не превысит.

У Вас тут примерно также.

b612
Offline
Зарегистрирован: 12.03.2017

ЕвгенийП пишет:

b612 пишет:

Подскажите, есть какой-нибудь способ разместить массив в памяти ардуино по заданному адресу ?

Есть (ну, при условии, что по заданному адресу есть достаточно свободного места).

Только не спрашивайте как это сделать до тех пор, пока не объясните для чего Вам это надо, посколько я абсолютно уверен, что это Вам не нужно, а задача такая возникла просто из-за непонимания чего-то другого.

я пишу массив в котором находятся пренастройки в EEPROM. 

Должна быть возможность заливать эти же настройки из hex-а точнее из файла .eep, сформированного совсем другой программой.

Опять же при перекомпиляции и перепрошивке программы, она должна нормально со старым EEPROM-ом

Т.е. я должен чётко задать где что будет лежать.

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

Так и задавайте структурой. Все настройки объединить в одну структуру и её использовать в обеих программах, чтобы при лбых изменениях структуры, менялось сразу в обеих.

b612
Offline
Зарегистрирован: 12.03.2017

ЕвгенийП пишет:

Так и задавайте структурой. Все настройки объединить в одну структуру и её использовать в обеих программах, чтобы при лбых изменениях структуры, менялось сразу в обеих.

Понятно, но эти массивы принадлежат совершенно разным частям программы и программы пишут разные люди и в разное время, вообщем там трудно договориться.

Проще было бы задать адреса железно.

Может быть объявить всю память одним массивом а потом просто определить указатели, но тогда тоже проблемы.

При рошивке одного массива будет наверно затираться вся память.

Вообщем придётся возвращаться к EEPROM.read(...

b707
Offline
Зарегистрирован: 26.05.2017

b612 пишет:

Вообщем придётся возвращаться к EEPROM.read(...

Вы явно не понимаете сути макроса EMEM - смысл его именно в том, что адреса размещения данных в ЕЕПРОМ выбираются автоматически. Так что Ваш вопрос "Как задать адреса для EMEM?"  совершенно бессмысленный и ответ только один - никак.

Если вам нужно размещать данные по конкретным адресам - работайте с eeprom_read_byte()

b612
Offline
Зарегистрирован: 12.03.2017

b707 пишет:

Вы явно не понимаете сути макроса EMEM - смысл его именно в том, что адреса размещения данных в ЕЕПРОМ выбираются автоматически. Так что Ваш вопрос "Как задать адреса для EMEM?"  совершенно бессмысленный и ответ только один - никак.

Если вам нужно размещать данные по конкретным адресам - работайте с eeprom_read_byte()

возможно. 

ноги начали расти из того, что надо было както разместить данные в еепроме, не тратя на это флэш.

А раз получилось разместить массивы при помощи EMEMа, то хотелось бы чтобы они размещались не где им вздумается

b707
Offline
Зарегистрирован: 26.05.2017

b612 пишет:

ноги начали расти из того, что надо было както разместить данные в еепроме, не тратя на это флэш.

ну, чудес-то не бывает - чтобы использовать ваши данные, что хранятся в EMEM - вы все равно сначала их в оперативку считываете

b707
Offline
Зарегистрирован: 26.05.2017

b612 пишет:

А раз получилось разместить массивы при помощи EMEMа, то хотелось бы чтобы они размещались не где им вздумается

А можете пояснить, зачем нужно писать массивы по фиксированным адресам? - мне вот опять кажется, что вы с сутью макроса ЕМЕМ не разобрались... Этот метод размещения данных в ЕЕПРОМ не требует знания адресов - ни для записи, ни для считывания.

Вы когда создаете массив в оперативке, например

int foo[32]

вас же не интересует, по какому адресу он создался? - вы вообще не работает с адресами, вы обращаетесь к массиву по имени. Ну и в случае EEMEM все ровно так же