Использование static в классе

orcsin
Offline
Зарегистрирован: 12.06.2015

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

Прочитал что в С/С++ можно использовать одну переменную на все объекты полученные от одного класса.

static int count = 0;

По сути проблема в том, что мне не хватает ОЗУ при создании множества объектов и некоторые переменные я хочу "объединить". Например

class ClassTimeInterval {
	private:
		RTC_DS1307 rtc1;	
		static DateTime timeNow;

...

Но не работает.

Вобще доступно ли такое на Ардуино? Может я не правильно прописываю?

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

А выделить память под статическую переменную не пробовал?

DateTime ClassTimeInterval::timeNow;

Клапауций 234
Offline
Зарегистрирован: 24.10.2016
class ClassTimeInterval {
	private:
		RTC_DS1307 rtc1;	
		static const DateTime timeNow;

 

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

Думаю, что проблема в том, о чём написал коллега Andy, но на всякий случай спрошу: "А что значит "не работает""? В чём это выражается?

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

В ардуине static работает по полной, как повелевает стандарт и воплощает GCC. Никакой специфики. Давайте полній код и вывод ошибки - чего подскажем. 

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

Logik пишет:

В ардуине static работает по полной, как повелевает стандарт и воплощает GCC. Никакой специфики. Давайте полній код и вывод ошибки - чего подскажем. 

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

orcsin
Offline
Зарегистрирован: 12.06.2015

Может я не понял, но DateTime timeNow; у меня не константа, она постоянно получает значение текущего времени.

class ClassTimeInterval {
	private:
		RTC_DS1307 rtc1;	
		static DateTime timeNow;

};
byte ClassTimeInterval::getStatusPWM(){
	timeNow = rtc1.now();
}

 

orcsin
Offline
Зарегистрирован: 12.06.2015

Вот ошибка, количество ошибок по количеству созданых объектов:

ClassTimeIntervalNew\ClassTimeIntervalNew.cpp.o: In function `ClassTimeInterval::getStatusPWM()':
C:\Users\Константин\Documents\Arduino\libraries\ClassTimeIntervalNew/ClassTimeIntervalNew.cpp:213: undefined reference to `ClassTimeInterval::timeNow'
C:\Users\Константин\Documents\Arduino\libraries\ClassTimeIntervalNew/ClassTimeIntervalNew.cpp:213: undefined reference to `ClassTimeInterval::timeNow'
C:\Users\Константин\Documents\Arduino\libraries\ClassTimeIntervalNew/ClassTimeIntervalNew.cpp:214: undefined reference to `ClassTimeInterval::timeNow'
C:\Users\Константин\Documents\Arduino\libraries\ClassTimeIntervalNew/ClassTimeIntervalNew.cpp:214: undefined reference to `ClassTimeInterval::timeNow'
C:\Users\Константин\Documents\Arduino\libraries\ClassTimeIntervalNew/ClassTimeIntervalNew.cpp:214: undefined reference to `ClassTimeInterval::timeNow'
ClassTimeIntervalNew\ClassTimeIntervalNew.cpp.o:C:\Users\Константин\Documents\Arduino\libraries\ClassTimeIntervalNew/ClassTimeIntervalNew.cpp:281: more undefined references to `ClassTimeInterval::timeNow' follow
collect2.exe: error: ld returned 1 exit status
Ошибка компиляции.
 

orcsin
Offline
Зарегистрирован: 12.06.2015

Клапауций 234 пишет:

class ClassTimeInterval {
	private:
		RTC_DS1307 rtc1;	
		static const DateTime timeNow;

 

C:\Users\Константин\Documents\Arduino\libraries\ClassTimeIntervalNew\ClassTimeIntervalNew.cpp: In member function 'byte ClassTimeInterval::getStatusPWM()':
C:\Users\Константин\Documents\Arduino\libraries\ClassTimeIntervalNew\ClassTimeIntervalNew.cpp:213:10: error: passing 'const DateTime' as 'this' argument of 'DateTime& DateTime::operator=(const DateTime&)' discards qualifiers [-fpermissive]
  timeNow = rtc1.now();
          ^
C:\Users\Константин\Documents\Arduino\libraries\ClassTimeIntervalNew\ClassTimeIntervalNew.cpp: In member function 'float ClassTimeInterval::calcPwmUp()':
C:\Users\Константин\Documents\Arduino\libraries\ClassTimeIntervalNew\ClassTimeIntervalNew.cpp:281:10: error: passing 'const DateTime' as 'this' argument of 'DateTime& DateTime::operator=(const DateTime&)' discards qualifiers [-fpermissive]
  timeNow = rtc1.now();
          ^
C:\Users\Константин\Documents\Arduino\libraries\ClassTimeIntervalNew\ClassTimeIntervalNew.cpp: In member function 'float ClassTimeInterval::calcPwmDown()':
C:\Users\Константин\Documents\Arduino\libraries\ClassTimeIntervalNew\ClassTimeIntervalNew.cpp:288:10: error: passing 'const DateTime' as 'this' argument of 'DateTime& DateTime::operator=(const DateTime&)' discards qualifiers [-fpermissive]
  timeNow = rtc1.now();
          ^
Ошибка компиляции.
 

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

orcsin

Если Вы хотите пользоваться статическими переменными класса, то сначала почитайте как это делается.

Во-первых, переменную нужно описать, т.е. выделить по неё память (см. пост Andy).

Во-вторых, обращаться к ней надо либо указывая имя класса

ClassTimeInterval::timeNow = rtc1.now();

или через любой экземпляр, но всегда помните, что она (эта переменная) одна на все экземпляры.

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

Ну не видя всего кода можна предположить наличие отсутствия  DateTime ClassTimeInterval::timeNow;

 

orcsin
Offline
Зарегистрирован: 12.06.2015

Так а где мне объявить - DateTime ClassTimeInterval::timeNow;

В test.h или в test.ino?

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

ino

orcsin
Offline
Зарегистрирован: 12.06.2015

В *.ino :)

Всем спасибо за помощь!!!

orcsin
Offline
Зарегистрирован: 12.06.2015

Программа вроде не большая, ещё не всё что хотел написал, а ОЗУ уже заканчивается. Пытался писать правильно, объяляю всякие переменные, а теперь не хватает памяти :(

Sketch uses 21 770 bytes (70%) of program storage space. Maximum is 30 720 bytes.
Global variables use 1 747 bytes (85%) of dynamic memory, leaving 301 bytes for local variables. Maximum is 2 048 bytes.
Low memory available, stability problems may occur.

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

Это сколько же "всяких переменных" надо объявить, чтобы израсходовать более полутора килобайт памяти...

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

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Автор хочет побить рекорд Тойоты в 11000 переменных?
Наверное просто массивы большие.

orcsin
Offline
Зарегистрирован: 12.06.2015

Да есть большие массивы для меню. У меня древоводное меню на 20 листов.

Вот все глобальные переменные, если что подскажите как сократить, буду благодарен :)

// Pins of Arduino
#define pinDigitalBuzzer	2
#define pinDigitalServos1	5
#define pinDigitalServos2 	6
// #define pinDigitalFanLed 	7

//********** LED LIGHT **********//
#define pinDigitalLedStrip	3
#define pinDigitalLedWhite	9
#define pinDigitalLedRed	10 
#define pinDigitalLedBlue	11

//********** Temperature **********//
#define pinDigitalTemperatureAqua1 14
#define pinDigitalTemperatureAqua2 15
#define pinDigitalTemperatureLed 16
#define pinDigitalTemperatureRoom 17

//********** 74HC595 ************//
#define pinDigitalData74HC595	8
#define pinDigitalClock74HC595	12
#define pinDigitalLatch74HC595	13

//********** Button ************//
#define  pinAnalogButtonMenu 	20
#define  pinAnalogButtonRelay	21

//********** pin74HC595 ************//
#define pin74HC595StatusLedTemperatureRelay1	0
#define pin74HC595StatusLedTemperatureRelay2 	1
#define pin74HC595StatusLedFilterRelay 			2
#define pin74HC595StatusLedAirRelay 			3
#define pin74HC595TemperatureRelay1 			4
#define pin74HC595TemperatureRelay2				5
#define pin74HC595FilterRelay 					6
#define pin74HC595AirRelay 						7

//**************** Declaration devices *****************//
LiquidCrystal_I2C lcd(0x27,16,2);
RTC_DS1307 rtc;
TwoSerialShiftRegister74HC595 sr74hc595 (pinDigitalData74HC595, pinDigitalClock74HC595, pinDigitalLatch74HC595);

//********************** Light ***********************//
DateTime ClassTimeInterval::timeNow;
const byte quantityColor = 4;
const byte quantityInterval = 2;
ClassTimeInterval ColorLightInterval[quantityColor][quantityInterval] = {
	{13, 20},
	{27, 34},
	{41, 48},
	{55, 62}
};

byte lightBrightnessColor[4];
byte lightPwmDuration[4][2]; // lightPwmDuration[Color][On-Off]

// bool statusLightOnAuto;
bool statusLight[4]; //0 - timer, 1 - on;

int timeLightTimer[4][2][2][2] = {};	// удалить позже
//byte timeLightTimer[selectedLight][selectedLightTimerInterval][selectedLightTimerOnOff][selectedTimerHM];

float pwmNow = 0.0;

byte timeSet[2]; 	// Масив временного хранения часов и минут таймеров; ?????????
DateTime now;   		// Считывает значения времени

bool selectedTimerHM;
const bool HOURS = 0;
const bool MINUTES = 1;

//********************* Temperature **************************//
typedef uint8_t DeviceAddress[8];

OneWire oneWire[] = {
	pinDigitalTemperatureAqua1,
	pinDigitalTemperatureAqua2,
	pinDigitalTemperatureLed,
	pinDigitalTemperatureRoom
};

DS18B20Lib sensorsTemperature[] = {
	&oneWire[0],
	&oneWire[1],
	&oneWire[2],
	&oneWire[3]
};

const byte sensorTemperatureCount = sizeof(oneWire)/sizeof(OneWire);

byte setTemperature[sensorTemperatureCount];			// Текущая температура: [0] - вода №1, [1] - вода №2, [2] - регулируемая температура;

bool statusSensor[4];	// 0 - auto, 1 - on;

/* DeviceAddress addresSensorTemperature[] = {
	{0x28, 0xFF, 0xBE, 0xD9, 0x64, 0x15, 0x02, 0xA3},
	{0x28, 0xFF, 0x0D, 0xAD, 0x64, 0x15, 0x03, 0x5A},
    {0x28, 0xFF, 0x01, 0x4C, 0x54, 0x16, 0x04, 0xB5},
	{0x28, 0xFF, 0xE5, 0x6F, 0x53, 0x16, 0x04, 0xF2}
}; */

//************************** Menu ***************************//
enum pageMenu:byte {
	MENU_DEFAULT_SET,							// 0;
	MENU_SCREEN_SAVER,							// 1;
	MENU_MAIN,									// 2;
	MENU_SENSOR_SELECT,							// 3;
	MENU_SENSOR_MODE,							// 4;
	MENU_SENSOR_SET,							// 5;
	MENU_LIGHT_SELECT,							// 6;
	MENU_LIGHT_MODE,							// 7;
	MENU_LIGHT_PWM_SET,							// 8;
	MENU_LIGHT_SUNSET_SET,						// 9;
	MENU_LIGHT_TAIMER_MODE,						// 10;
	MENU_LIGHT_TAIMER_INTERVAL_SELECT,			// 11;
	MENU_LIGHT_TAIMER_INTERVAL_SELECT_ON_OFF,	// 12;
	MENU_LIGHT_TAIMER_INTERVAL_SET_H_M,			// 13;
	MENU_FOOD_SELECT,							// 14;
	MENU_FOOD_TIME_SELECT,						// 15;
	MENU_FOOD_TIME_SET_H_M,						// 16;
	MENU_TIME_SET_H_M,							// 17;
	MENU_DOSAGE_SET,							// 18;
	} currentMenu;

enum lightTimerInterval:bool {
	FIRST_INT,
	SECOND_INT
} selectedLightTimerInterval;

enum lightTimerOnOff:bool {
	S_OFF,
	S_ON
} selectedLightTimerOnOff;

//**************** Food *****************//
enum food:bool {
	FOOD_1,
	FOOD_2
} selectedFood;

enum dose:bool {
	DOSE_1,
	DOSE_2
} selectedDose;

enum timeFood:byte {
	TIME_FOOD_1,
	TIME_FOOD_2,
	TIME_FOOD_3,
	TIME_FOOD_4
} selectedTimeFood;

byte timeFoodTimer[4][2][2];	// timeFoodTimer[selectedFood][selectedTimeFood][selectedTimerHM];
byte doseFood[2];

//**************** Button *****************//
const byte RELAY_TEMPERATURE1  	= 1;
const byte RELAY_TEMPERATURE2  	= 3;
const byte RELAY_FILTER    		= 4;
const byte RELAY_AIR   			= 6;

const byte BUTTON_NONE   		= 0;
const byte BUTTON_CANCEL  		= 6;
const byte BUTTON_LEFT     		= 5;
const byte BUTTON_DOWN   		= 4;
const byte BUTTON_UP   			= 3;
const byte BUTTON_RIGHT 		= 2;
const byte BUTTON_SELECT 		= 1;

byte pressedButton;
long lastTimeWhenPressTheButton = 0;

//****************** Other *****************//
bool statusEnableSound  = false;	//0 - off, 1 - on;
bool needRecordEEPROM = 0;

bool enableRelay[] = {true, true, true, true};

byte matrixMenu[45][5] = { // {Номер меню, родительское меню, дочернее меню, Х_курсор, Y_курсор}; menu
	{0, 0, 1, 0, 0}, {0, 0, 1, 0, 1},
	{1, 0, 2, 0, 0},
	{2, 1, 3, 0, 0}, {2, 1, 6, 0, 1}, {2, 1, 14, 10, 0}, {2, 1, 17, 10, 1},
	{3, 2, 4, 0, 0}, {3, 2, 4, 0, 1}, {3, 2, 4, 8, 0}, {3, 2, 4, 8, 1},
	{4, 3, 5, 0, 0}, {4, 3, 5, 0, 1},
	{5, 4, 5, 0, 0},
	{6, 2, 7, 0, 0}, {6, 2, 7, 0, 1}, {6, 2, 7, 8, 0}, {6, 2, 7, 8, 1},
	{7, 6, 9, 0, 1}, {7, 6, 8, 8, 0}, {7, 6, 10, 8, 1},
	{8, 7, 8, 0, 0},
	{9, 7, 9, 6, 0}, {9, 7, 9, 6, 1},
	{10, 7, 11, 0, 0}, {10, 7, 11, 0, 1},
	{11, 10, 12, 6, 0}, {11, 10, 12, 6, 1},
	{12, 11, 13, 6, 0}, {12, 11, 13, 6, 1},
	{13, 12, 13, 6, 0}, {13, 12, 13, 6, 1},
	{14, 2, 15, 0, 0}, {14, 2, 15, 0, 1}, {14, 2, 18, 8, 0}, {14, 2, 18, 8, 1},
	{15, 14, 16, 0, 0}, {15, 14, 16, 0, 1}, {15, 14, 16, 8, 0}, {15, 14, 16, 8, 1},
	{16, 15, 16, 6, 0}, {16, 15, 16, 6, 1},
	{17, 2, 17, 6, 0}, {17, 2, 17, 6, 1},
	{18, 14, 18, 0, 0}
};

byte elementsMenu[19][2] = { // {, Start, End};
	{0, 1}, // (x, y, x+y)
	{2, 2},
	{3, 6},
	{7, 10},
	{11, 12},
	{13, 13},
	{14, 17},
	{18, 20},
	{21, 21},
	{22, 23},
	{24, 25},
	{26, 27},
	{28, 29},
	{30, 31},
	{32, 35},
	{36, 39},
	{40, 41},
	{42, 43},
	{44, 44}
};

byte curentPosCursor = 0;
byte countStepMenu = 0;
byte lastCurentPosCursor[8];
bool enableCursor = false;
bool backMenu;

enum colorLight:byte {STRIP, WHITE, RED, BLUE} selectedLight;
enum sensor:byte {AKB_1_T, AKB_2_T, LED_1_T, LED_2_T} selectedSensor;
// enum lightTimerInterval {FIRST_INT, SECOND_INT} selectedLightTimerInterval;
// enum lightTimerOnOff {S_ON, S_OFF} selectedLightTimerOnOff;

enum status:bool {AUTO_SENSOR , ON_SENSOR};

unsigned int delayAfterWelcome = 1000;
int delayTimeAfterGoToMainMenu = 30000;
int posCursorX, posCursorY;
bool activateDelayTimeAfterMenuSave = false;

byte lightPwmOn;
byte lightPwmOff;

byte hoursTime;
byte minutesTime;

bool checkNeedSave = false;

float currentTemperature[sensorTemperatureCount];

enum relay:byte {
	AKB_1,
	AKB_2,
	FILTER,
	AIR};

const int voltageIntervals[6] = {950, 870, 815, 780, 680, 350};
int delayTimeAfterPressButton = 90;
int count;

И вот ещё моя либа:

class ClassTimeInterval {
	private:
		static DateTime timeNow;
		RTC_DS1307 rtc1;	
		
		enum status:byte {PWM_OFF, PWM_ON, PWM_UP, PWM_DOWN};
		
		// input data
		byte address;
		byte maxPwmValue;
		byte turnOnDuration;	
		byte turnOffDuration;
		byte turnOnHours; 		
		byte turnOnMinutes;	
		byte turnOffHours;		
		byte turnOffMinutes;
		
		void readEEPROM();
		
		//internal data
		long turnOnStartToSeconds;	// сумируется из данных
		long turnOnFinishToSeconds;	// sunriseStartToMinutes + turnOnDuration
		long turnOffStartToSeconds;		// sunsetFinishToMinutes - turnOffDuration
		long turnOffFinishToSeconds;	// сумируется из данных
		int turnOnDurationToSeconds;
		int turnOffDurationToSeconds;
		
		// output data
		
		// void calculationTimeOfPoints();
		long CalculationTimeToSeconds(long hours, long minutes, long seconds);
		
	public:
		long timeNowToSeconds;
		
		ClassTimeInterval(byte addressEEPROM);
		ClassTimeInterval(byte addressEEPROM, byte pwmValue,
			byte onDuration, byte offDuration,
			byte onHours, byte onMinutes,
			byte offHours, byte offMinutes);
		
		void initData();
		void updateData();
		
		void putTurnOnHours(byte hours);
		void putTurnOnMinutes(byte minutes);
		void putTurnOffHours(byte hours);
		void putTurnOffMinutes(byte minutes);
		void putTurnOnDuration(byte minutes);
		void putTurnOffDuration(byte minutes);
		void putMaxPwmValue(byte pwmValue);
		
		byte getTurnOnHours();
		byte getTurnOnMinutes();
		byte getTurnOffHours();
		byte getTurnOffMinutes();
		byte getTurnOnDuration();
		byte getTurnOffDuration();
		byte getMaxPwmValue();
		
		
		void saveTurnOnHours();
		void saveTurnOnMinutes();
		void saveTurnOffHours();
		void saveTurnOffMinutes();
		void saveTurnOnDuration();
		void saveTurnOffDuration();
		
		void increaseTurnOnHours();
		void increaseTurnOnMinutes();
		void increaseTurnOffHours();
		void increaseTurnOffMinutes();
		void increaseTurnOnDuration();
		void increaseTurnOffDuration();
		
		void decreaseTurnOnHours();
		void decreaseTurnOnMinutes();
		void decreaseTurnOffHours();
		void decreaseTurnOffMinutes();
		void decreaseTurnOnDuration();
		void decreaseTurnOffDuration();

		
		
		
		float getCurrentPwmValue();
		byte getStatusPWM();
		float calcPwmValue(byte statusPwm1);
		float calcPwmUp();
		float calcPwmDown();
	
};

плюс я так понимаю жрут общие библиотеки:

#include <Wire.h>
#include <OneWire.h>
#include <DS18B20Lib.h>
#include <LiquidCrystal_I2C.h>
#include <RTClib.h>
#include <TwoSerialShiftRegister74HC595.h>
#include <EEPROM.h>
#include <ClassTimeIntervalNew.h>
orcsin
Offline
Зарегистрирован: 12.06.2015

Это только глобальные переменные.

Но надо ещё будет дописать кое что из функционала...

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

matrixMenu  сразу в PROGMEM - и 225 байт ОЗУ свободны. Остальные большие массивы туда же. Либы тоже под плдозрением, каждую препарировать индивидуально - исключаете на время из проекта, коментируете обращения к ней чтоб скетч собрался и смотрите как её отсутствие скажется на используемой памяти. Возвращаете и переходите к следующей. Выводы в конце. Кстати, результатами здесь можете поделится.

orcsin
Offline
Зарегистрирован: 12.06.2015

Logik, классная штука, но только я не понял, какую память он жрёт и сколько её в наличии и осталось.

Перевёл большой массив в PROGMEM получил до и после:

/* Sketch uses 21 818 bytes (71%) of program storage space. Maximum is 30 720 bytes.
Global variables use 1 747 bytes (85%) of dynamic memory, leaving 301 bytes for local variables.
 Maximum is 2 048 bytes */
 
/*  Sketch uses 21 820 bytes (71%) of program storage space. Maximum is 30 720 bytes.
Global variables use 1 523 bytes (74%) of dynamic memory, leaving 525 bytes for local variables.
 Maximum is 2 048 bytes */

Освободил 224 байта в ОЗУ, но во флеше прибавилось только 2 байта

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

kisoft пишет:
Автор хочет побить рекорд Тойоты в 11000 переменных? Наверное просто массивы большие.

Ну переменные бывают разные. Среди них бывают как ни странно константы. Ладно если бы те которые в программе сидят,  и программисты выбирают под конечные ситуации. Так есть константы которые подбираются пользователем. Скорее из-за них и городится меню.  Но если процедурное программирование обходится минимумом переменных, то объектное генерирует их как бы не по максимуму. Но если в больших что ОЗУ под код что ОЗУ под данные одно и тоже. То здесь это разные вещи-флеш память и ОЗУ. Про еепром я не говорю. Это даже не ОЗУ. 

 Мой совет . Определитесь что делать переменными, а что делать константами. Ну и что будет константами которые переменные, но меняются через меню. 

const int DATA_pin=2; // и не надо боятся такой записи. В ОЗУ она не занимает место
const byte MAP[]={1,2,3,4}; // такая же песня. ОЗУ не потребляет.

ПС:https://goo.gl/vASyD5

orcsin
Offline
Зарегистрирован: 12.06.2015

А enum что сразу кладёт данные во флешь?

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

orcsin пишет:

А enum что сразу кладёт данные во флешь?

У меня подозрение, что  enum это просто формат данных. В коде это всего навсего байт.

orcsin
Offline
Зарегистрирован: 12.06.2015

qwone, не много вас не понял...

Все глобальные переменные я привёл выше, других больше нет.

Констант, кроме масивом меню у меня нет. #define вроде тоже не занимаю ОЗУ.

orcsin
Offline
Зарегистрирован: 12.06.2015

Вобщем пока только за счёт ... получилось уменьшить расход ОЗУ:

Было:

Sketch uses 21 770 bytes (70%) of program storage space. Maximum is 30 720 bytes.
Global variables use 1 747 bytes (85%) of dynamic memory, leaving 301 bytes for local variables. Maximum is 2 048 bytes.
Low memory available, stability problems may occur.

Стало:

Sketch uses 21 778 bytes (70%) of program storage space. Maximum is 30 720 bytes.
Global variables use 1 467 bytes (71%) of dynamic memory, leaving 581 bytes for local variables. Maximum is 2 048 bytes.

Чувствительно, но мало :(

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

ок. а, зачем это хранить так

byte matrixMenu[45][5] = { // {Номер меню, родительское меню, дочернее меню, Х_курсор, Y_курсор}; menu

а, не так?:

byte Номер меню;
byte родительское меню;
byte дочернее меню;
byte Х_курсор;
byte Y_курсор;

 

 

orcsin
Offline
Зарегистрирован: 12.06.2015

У каждого меню свои значения этих констант.

byte Номер меню;
byte родительское меню;
byte дочернее меню;
byte Х_курсор;
byte Y_курсор;

надо написать 45 раз.

Name Parent Child Xcur Ycur
MenuDefaultSet() 0 0 1 0 0
0 0 1 0 1
MenuScreenSaver() 1 0 2 0 0
MenuMain() 2 1 3 0 0
2 1 6 0 1
2 1 14 10 0
2 1 17 10 1
MenuSensorSelect() 3 2 4 0 0
3 2 4 0 1
3 2 4 8 0
3 2 4 8 1

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

orcsin
Offline
Зарегистрирован: 12.06.2015

ПРикол в том, что у меня на разных страницах меню, разные позиции курсоров, поэтому приходится каждую страницу программировать отдельно

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

ну да экран 16 на 2 это большой размер. 32 позиции. Глядишь уже одна координата пропала.

х=pos%16;

y=pos/16;

 а так еще проще

lcd.setCursor(pos%16,pos/16);

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

qwone пишет:

х=pos%16;

y=pos/16;

 а так еще проще

lcd.setCursor(pos%16,pos/16);

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

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

orcsin пишет:

Logik, классная штука, но только я не понял, какую память он жрёт и сколько её в наличии и осталось.

...

Освободил 224 байта в ОЗУ, но во флеше прибавилось только 2 байта

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

Если Вы их просто описываете в тексте программы, они записываются в PROGMEM, а перед началом работы (после включения питания) переписываются в OЗУ. Если Вы при описании массива исплоьзуете PROGMEM, то они там и остаются, а в ОЗУ не копируются. Соответственно, места там не занимают. Но в PROGMEM они остаются в любом случае.

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

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

qwone пишет:

х=pos%16;

y=pos/16;

 а так еще проще

lcd.setCursor(pos%16,pos/16);

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

Этот совет касается оптимизации, и мне кажется, об этом нужно писать, т.к. в подавляющем большинстве случаев это несущественно. В частности - несущественно с точки зрения экономии оперативной памяти, о чем спрашивает ТС. Кроме того, в данном случае совет вредный: деление на степени двойки реализуется сдвигами. Это в любом случае лучше вызова функции.

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

ЕвгенийП Не понял на счет процессора. Но логические операции и сдвиг должен быть.

х=pos&15;

y=(pos>>4)&1;

 а так еще проще

lcd.setCursor(pos&15,(pos>>4)&1);

ПС: Просто упаковать плотнее данные и весь секрет.

orcsin
Offline
Зарегистрирован: 12.06.2015

qwone пишет:

ну да экран 16 на 2 это большой размер. 32 позиции. Глядишь уже одна координата пропала.

х=pos%16;

y=pos/16;

 а так еще проще

lcd.setCursor(pos%16,pos/16);

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

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

В одном байте восем бит.  х-х-х-х-х-х-х-х , где х это 0 или 1.  в один байт можно записать число от 0 до 255. у вас позиций на курсоре 2*16=32 . И можно Хкур и Yкур упаковать в один байт   х-х-х-Yкур-Хкур-Хкур-Хкур-Хкур . Ну а дальше просто извлечение этих значений.

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

int timeLightTimer[4][2][2][2] = {};    // удалить позже

это звучит гордо! 

Наверное я убогий, никогда такие массивы не были нужны. 4 уровня - это круто!

Удалить позже статчиеский массив это "прикольно|.

 

orcsin
Offline
Зарегистрирован: 12.06.2015

kisoft, вы попонтоваться или посоветовать что то полезное?

orcsin
Offline
Зарегистрирован: 12.06.2015

qwone пишет:

В одном байте восем бит.  х-х-х-х-х-х-х-х , где х это 0 или 1.  в один байт можно записать число от 0 до 255. у вас позиций на курсоре 2*16=32 . И можно Хкур и Yкур упаковать в один байт   х-х-х-Yкур-Хкур-Хкур-Хкур-Хкур . Ну а дальше просто извлечение этих значений.

Примерно понял, но я так понимаю это будет плохо читаемо? Так я вижу координат в явном виде, а в вашем случае наверное нет.

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

orcsin пишет:

Примерно понял, но я так понимаю это будет плохо читаемо? Так я вижу координат в явном виде, а в вашем случае наверное нет.

 

Вот я это хотел услышать! Проблемы в программах у программистов связаны не с программами, а проблемами с мозгами этих программистов. Вот вы привыкли, что памяти много, и вы не умеете не только читать экономные программы, но и писать их.  У вас два пути или искать более мощные компьютеры или учится читать и писать такие программы. Это не в обиду к вам. Просто ваш код вас научит, или не научит. Программирование это все-таки практика. 

orcsin
Offline
Зарегистрирован: 12.06.2015

не буду создавать новую тему, поэтому спрошу тут:

У меня есть 4 канала света по 2 рабочих интервала и я создаю объекты вот так:

const PROGMEM byte quantityColor = 4;
const PROGMEM byte quantityInterval = 2;
ClassTimeInterval ColorLightInterval[quantityColor][quantityInterval];

Для всех 4 каналов(quantityColor) значения приватных переменных в классе

byte maxPwmValue;
byte turnOnDuration;	
byte turnOffDuration;

одинаковые для обоих интервалов(quantityInterval).

Считываю я эти значения с первого интервала ColorLightInterval[quantityColor][0], а вот записывать прийдётся в оба, можно как то эти два значения объединить, может через ссылку, но класс создаёт массив объектов и ему без разницы это массив [4][2] или [8].

Есть какие то мысли?

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

orcsin пишет:

Примерно понял, но я так понимаю это будет плохо читаемо? Так я вижу координат в явном виде, а в вашем случае наверное нет.

qwone пишет:

Вот я это хотел услышать!

я не хотел, но услышал - что препятствует запустить виндовый калькулятор в режиме "Программист"?

orcsin
Offline
Зарегистрирован: 12.06.2015

qwone пишет:

orcsin пишет:

Примерно понял, но я так понимаю это будет плохо читаемо? Так я вижу координат в явном виде, а в вашем случае наверное нет.

 

Вот я это хотел услышать! Проблемы в программах у программистов связаны не с программами, а проблемами с мозгами этих программистов. Вот вы привыкли, что памяти много, и вы не умеете не только читать экономные программы, но и писать их.  У вас два пути или искать более мощные компьютеры или учится читать и писать такие программы. Это не в обиду к вам. Просто ваш код вас научит, или не научит. Программирование это все-таки практика. 

Свою программу я почти написал, теперь в принципе и занимаюсь оптимизацией кода, что то вычитал новое и начию переписывать код переодически. До этого как то не понимал классы, а потом попалась хорошая книжка и всё стало понятно и стал переписывать массивы не понятных данных в классы и т.д. Вот теперь про PROGMEM знаю :) Чуть помогло.

qwone пишет:

В одном байте восем бит.  х-х-х-х-х-х-х-х , где х это 0 или 1.  в один байт можно записать число от 0 до 255. у вас позиций на курсоре 2*16=32 . И можно Хкур и Yкур упаковать в один байт   х-х-х-Yкур-Хкур-Хкур-Хкур-Хкур . Ну а дальше просто извлечение этих значений.

А можно пример кодировки моих координат, то что вы написали выше, так сказать для закрепления, например:

lcd.setCursor(7, 1);

Хотя мне кажется что когда я вижу 7,1, я могу понять где находится курсор, но если там будет цифра например 01010111 или 12, я конечно может выучу со временем коды всех 32 позиций, но с наскока такое будет трудно понять...

orcsin
Offline
Зарегистрирован: 12.06.2015

Клапауций 234 пишет:

orcsin пишет:

Примерно понял, но я так понимаю это будет плохо читаемо? Так я вижу координат в явном виде, а в вашем случае наверное нет.

qwone пишет:

Вот я это хотел услышать!

я не хотел, но услышал - что препятствует запустить виндовый калькулятор в режиме "Программист"?

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

Оптимизация штука нужная и полезная, но иногда мне кажется прозрачность кода лучше :)

А то через месяц хрен поймёшь что написал :)

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

orcsin пишет:

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

мне не понятно, откуда у тебя, вообще, эта картина берётся, если должно быть

byte Номер меню;
byte родительское меню;
byte дочернее меню;
byte Х_курсор;
byte Y_курсор;

как я писал выше. что за чехарда там у тебя с курсором - забыл курсор в одном месте, вернулся взад - курсор у тебя не в начальной позиции, а чёрти где?

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

orcsin пишет:

А можно пример кодировки моих координат, то что вы написали выше, так сказать для закрепления, например:

lcd.setCursor(7, 1);

Хотя мне кажется что когда я вижу 7,1, я могу понять где находится курсор, но если там будет цифра например 01010111 или 12, я конечно может выучу со временем коды всех 32 позиций, но с наскока такое будет трудно понять...

Опять вы меня не поняли в lcd.setCurcor(7,1); нет расхода памяти.  А вот в lcd.setCurcor(matrixMenu[i][4],matrixMenu[i][5]); уже есть . то есть matrixMenu есть лишняя колонка. И сокращать надо так  lcd.setCurcor(matrixMenu[i][4]%16,matrixMenu[i][4]/16);  И ничего помнить не надо. Оптимизация идет не только ради оптимизации, но и удобства программирования. Разве, что кострукция выражений усложнилась. Так и в русском языке. Есть же простые предложения, но на деле приходим к большим и сложным.

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

----

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

orcsin пишет:

...но если там будет цифра например 01010111 или 12, я конечно может выучу со временем коды всех 32 позиций...

Вы привыкли пользоваться десятичной системой?

Сколько чисел можно представить в десятичной системе? Миллон? Ммиллиард? Болше?

Вы всерьез утверждаете, что их все Вы выучили?

orcsin
Offline
Зарегистрирован: 12.06.2015

Клапауций 234 пишет:

orcsin пишет:

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

мне не понятно, откуда у тебя, вообще, эта картина берётся, если должно быть

byte Номер меню;
byte родительское меню;
byte дочернее меню;
byte Х_курсор;
byte Y_курсор;

как я писал выше. что за чехарда там у тебя с курсором - забыл курсор в одном месте, вернулся взад - курсор у тебя не в начальной позиции, а чёрти где?

Вот сруктура меню, стрелочки перехода в гугл док исчезли. Берюзовые клетки с ">" это возможные положения курсора

https://docs.google.com/spreadsheets/d/1WP253M536Bz-2Sz5sBUCzdEJT4MSMXNe...

а массив

const PROGMEM byte matrixMenu[45][5] = { // {Номер меню, родительское меню, дочернее меню, Х_курсор, Y_курсор}; menu
	{0, 0, 1, 0, 0}, {0, 0, 1, 0, 1},
	{1, 0, 2, 0, 0},
	{2, 1, 3, 0, 0}, {2, 1, 6, 0, 1}, {2, 1, 14, 10, 0}, {2, 1, 17, 10, 1},
	{3, 2, 4, 0, 0}, {3, 2, 4, 0, 1}, {3, 2, 4, 8, 0}, {3, 2, 4, 8, 1},
	{4, 3, 5, 0, 0}, {4, 3, 5, 0, 1},
	{5, 4, 5, 0, 0},
	{6, 2, 7, 0, 0}, {6, 2, 7, 0, 1}, {6, 2, 7, 8, 0}, {6, 2, 7, 8, 1},
	{7, 6, 9, 0, 1}, {7, 6, 8, 8, 0}, {7, 6, 10, 8, 1},
	{8, 7, 8, 0, 0},
	{9, 7, 9, 6, 0}, {9, 7, 9, 6, 1},
	{10, 7, 11, 0, 0}, {10, 7, 11, 0, 1},
	{11, 10, 12, 6, 0}, {11, 10, 12, 6, 1},
	{12, 11, 13, 6, 0}, {12, 11, 13, 6, 1},
	{13, 12, 13, 6, 0}, {13, 12, 13, 6, 1},
	{14, 2, 15, 0, 0}, {14, 2, 15, 0, 1}, {14, 2, 18, 8, 0}, {14, 2, 18, 8, 1},
	{15, 14, 16, 0, 0}, {15, 14, 16, 0, 1}, {15, 14, 16, 8, 0}, {15, 14, 16, 8, 1},
	{16, 15, 16, 6, 0}, {16, 15, 16, 6, 1},
	{17, 2, 17, 6, 0}, {17, 2, 17, 6, 1},
	{18, 14, 18, 0, 0}
};

это координаты каждого положения курсора и пути вверх и вниз для этого положения.

Где то же мне это нужно хранить. Пока ни чего лучшего в голову мне не пришло, если подскажите - буду благодарен.

orcsin
Offline
Зарегистрирован: 12.06.2015

qwone пишет:

Опять вы меня не поняли в lcd.setCurcor(7,1); нет расхода памяти.  А вот в lcd.setCurcor(matrixMenu[i][4],matrixMenu[i][5]); уже есть . то есть matrixMenu есть лишняя колонка. И сокращать надо так  lcd.setCurcor(matrixMenu[i][4]%16,matrixMenu[i][4]/16);  И ничего помнить не надо. Оптимизация идет не только ради оптимизации, но и удобства программирования. Разве, что кострукция выражений усложнилась. Так и в русском языке. Есть же простые предложения, но на деле приходим к большим и сложным.

Я правильно понял, что для lcd.setCurcor(7,1) matrixMenu[i][4] = 16+7=23 ?

Тогда 23%16 = 7, а 23/16 = 1 ?

 

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

orcsin пишет:

Я правильно понял, что для lcd.setCurcor(7,1) matrixMenu[i][4] = 16+7=23 ?

Тогда 23%16 = 7, а 23/16 = 1 ?

Ну да 23%16 = 7 (остаток от деления 23 на 16 равно 7. А  целая часть 23/16 равна 1.

Что бы вам понятнее было 23%10 будет 3 (остаток от деления на 10). А вот 23/10 будет 2. 0.3 усечется так как позиция (int)

ПС: 23=0х17=B00010111 . Все это одно и то же число. только первое в десятичном, второе в шеснадцатиричном а третье в двоичном.

 lcd.setCurcor(7,1)  можно записать так  lcd.setCurcor(0х17%0х10,0х17/0х10) . где вместо 0х17 можно почтавить ячейку из matrixMenu[i][4]

ППС : 16=0х10=B00010000 . Это что бы тупых вопросов не было.