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

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

andriano пишет:

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

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

Sketch uses 59 462 bytes (23%) of program storage space. Maximum is 253 952 bytes.
Global variables use 3 120 bytes (38%) of dynamic memory, leaving 5 072 bytes for local variables. Maximum is 8 192 bytes.
)))

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

ДА это как минимум МЕГА 2560, но принципиально в данном случае нужно в нано уместится :)

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

с появлением PROGMEM в моей программе начались какие то глупости:

Привожу куски кода:

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

int FindPressedButton(int _valueVoltageButton){	
	static int value;	
	for (int i = 0; i < 6; i++) {
		
		if (_valueVoltageButton > voltageIntervals[i]){
Serial.print("i - ");
Serial.println(i);			
Serial.print("_valueVoltageButton - ");
Serial.println(_valueVoltageButton);
Serial.print("voltageIntervals[i] - ");
Serial.println(voltageIntervals[i]);			
			if (value == i){
				count++;
				if (count == 3) {
					count = 0;

					return i+1;
				}
				return 0;
			} else {
				value = i;
Serial.print("value - ");
Serial.println(value);				
				return 0;
			}
		}
	}
	return 0;
}

на выходе получаю:

Welcome()
i - 4
_valueVoltageButton - 859
voltageIntervals[i] - 65
value - 4
pressedButton - 0
i - 4
_valueVoltageButton - 844
voltageIntervals[i] - 65
pressedButton - 0
i - 4
_valueVoltageButton - 844
voltageIntervals[i] - 65
pressedButton - 0
i - 4
_valueVoltageButton - 845
voltageIntervals[i] - 65
pressedButton - 5
 

Откуда voltageIntervals[i] - 65 ???

Убираю PROGMEM из строки (int voltageIntervals[6]   = {950, 870, 815, 780, 680, 350};) :

i - 2
_valueVoltageButton - 858
voltageIntervals[i] - 815
pressedButton - 0
i - 2
_valueVoltageButton - 858
voltageIntervals[i] - 815
pressedButton - 0
i - 2
_valueVoltageButton - 859
voltageIntervals[i] - 815
pressedButton - 3

По ходу появляются ошибки в ОЗУ, в чём проблема?
 

 

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

orcsin пишет:

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

Цитирую своё сообщение:

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

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

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

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

Я удивился 4 уровневому массиву. В чем тут понты?

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

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

 

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

kisoft пишет:

Научите, как можно удалить статический массив? Буду очень благодарен.

я тебя научу - выделяешь в текстовом редакторе строку массива и нажимаешь клавишу "Delete".

всё. с тебя 1$

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

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

kisoft пишет:

Научите, как можно удалить статический массив? Буду очень благодарен.

я тебя научу - выделяешь в текстовом редакторе строку массива и нажимаешь клавишу "Delete".

всё. с тебя 1$


Перечислил на карту

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

kisoft, ну вы крайне обидчивый :)

Такой массив был для меня удобен в плане обращения к нему

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

первая строка - цвет света - синий, красный, белый, зелёный

вторая строка  - интервал - первый, второй

третья строка -действие - включение, выключение

четвёртая строка - время - часы, минут.

В таком виде массив был для меня более читабелен, чем int timeLightTimer[32], так я вижу сколько цветов, сколько интервалов времени.

А про удалить, тут полностью прав Клапауций 234, нужно было просто удалить клавишей Delete.

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

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

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

Обидчивый? Возможно. Хотя, честно говоря мне по барабану, нет так нет. Не нужна помощь - не вопрос.

PROGMEM константы нужно считывать, увы, это не АРМ, например, PROGMEM

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

kisoft, спасибо.

Как то я сразу на заметил "pgm_read_word(data)";

Подскажите только пожалуйста как мне обращаться к данным этого массива через pgm_read_word(data);

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}
};

matrixMenu[45][3]   это pgm_read_word(matrixMenu+((45-1)*5 + 3)), так?

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

Почему word, массив байтов, читать нужно байты? pgm_read_byte?

И откуда взялся matrix[45][3] - он за пределами массива. Тогда уж matrix[44][3] и вычитать из индекса не нужно.

Можно еще так сделать: pgm_read_byte(&matrix[44][3]); Но это я не проверял, хотя, в принципе должно работать, короче нужно проверять.

 

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

Пытаюсь сэкономить память:

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

byte setTemperature[pgm_read_byte(&sensorTemperatureCount)];

в итоге получаю:

error: statement-expressions are not allowed outside functions nor in template-argument lists

Получается нельзя использовать константы PROGMEM при объявлении массивов?

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

Вот так тоже не работает:

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

switch (pressedButton) {
		case pgm_read_byte(&RELAY_TEMPERATURE1): // 1

		break;
		case pgm_read_byte(&RELAY_TEMPERATURE2): // 3

		break;
		case pgm_read_byte(&RELAY_FILTER):		//4

		break;
		case pgm_read_byte(&RELAY_AIR):		//5

		break;
	}

Так просто нельзя делать или это как то обходится?

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

orcsin пишет:

Получается нельзя использовать константы PROGMEM при объявлении массивов?

Нет, не получается. Константы можно, а вот вызовы функций - нельзя.

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

orcsin, объясните, как именно Вы пытаетесь сэкономить память? И при чем здесь PROGMEM?

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

orcsin пишет:

Вот так тоже не работает:

...

Так просто нельзя делать или это как то обходится?

orcsin, 

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

Ну, вот что Вы написали:

const PROGMEM byte RELAY_TEMPERATURE1  	= 1;

Вы понимаете. что означает слово const? Это означает КОНСТАНТА. Ну, а если она конастанта, то нафига ж Вы её менять пытаетесь?

pgm_read_byte(&RELAY_TEMPERATURE1)

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

Кроме того, Вы знаете, что должно идти после слова case? Константа интегрального типа, а Вы что туда пихаете?

Почитайте книжку по языку (я Вам уже советовал это в посте №9). Без этого Вы так и будете как слепой котёнок тыкаться, авось компилятор схавает. Но он ведь может схавать, но скомпилировать совсем не тот код, которого Вы ожидаете.

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

andriano пишет:

orcsin, объясните, как именно Вы пытаетесь сэкономить память? И при чем здесь PROGMEM?

В данном случае у меня пролема с ОЗУ.  Её осталось  мало. Выше мне подсказали PROGMEM, благодаря которой можно часть переменых переместить во флешь память. Ну на сколько я это понял.

Вот и пробую сделать именно это.

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

orcsin пишет:

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

ну, ок - ты что-то где-то прочитал.

а, как ты собрался менять переменные, которые возможно изменить, переписав флеш?

*так, чисто практический интерес имею - хочу писать флеш из исполняемого кода.

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

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

orcsin, 

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

Ну, вот что Вы написали:

const PROGMEM byte RELAY_TEMPERATURE1  	= 1;

Вы понимаете. что означает слово const? Это означает КОНСТАНТА. Ну, а если она конастанта, то нафига ж Вы её менять пытаетесь?

pgm_read_byte(&RELAY_TEMPERATURE1)

Почитайте книжку по языку (я Вам уже советовал это в посте №9). Без этого Вы так и будете как слепой котёнок тыкаться, авось компилятор схавает. Но он ведь может схавать, но скомпилировать совсем не тот код, которого Вы ожидаете.

1. Да не пытаюсь вроде осозновать то что пишу :)

2. Я вроде не пытаюсь изменить константу, а только вызываю её значение через

pgm_read_byte(&RELAY_TEMPERATURE1).

Или я что то не понимаю?

Несколько книг я прочёл, много дало, но видимо там не всё есть с чем приходится сталкиваться. Если посоветуете какую то конкретную книгу, буду очень благодарен. Я про классы прочёл несколько книг, и только в 5ой было написано так, что хоть как то стало понятно.

И про case,

const PROGMEM byte RELAY_TEMPERATURE1  	= 1;
const byte RELAY_TEMPERATURE1  	= 1;

в этих двух строках же вроде один и тот же тип указан, просто один займёт место в ОЗУ, а другой нет. Или я опять что то упустил? На сколько я понял то PROGMEM используется для этого, что бы освободить ОЗУ.

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

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

orcsin пишет:

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

ну, ок - ты что-то где-то прочитал.

а, как ты собрался менять переменные, которые возможно изменить, переписав флеш?

*так, чисто практический интерес имею - хочу писать флеш из исполняемого кода.

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

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

orcsin пишет:

2. Я вроде не пытаюсь изменить константу, а только вызываю её значение 

Понятия "вызывать значение" нет. Вы пытаетесь присвоеить ей значение, а это и есть поменять её. Она у Вас при описании была 1, а Вы пытаетесь туда что-то другое запихать.

orcsin пишет:

И про case,

const PROGMEM byte RELAY_TEMPERATURE1  	= 1;
const byte RELAY_TEMPERATURE1  	= 1;

в этих двух строках же вроде один и тот же тип указан, просто один займёт место в ОЗУ, а другой нет. Или я опять что то упустил? На сколько я понял то PROGMEM используется для этого, что бы освободить ОЗУ.

Ни в том ни в другом случае RELAY_TEMPERATURE1 не будет занимать ОЗУ. Но и поменять её нельзя, т.к. костанта. Вот Вы сказали, что она 1 - так она 1 и будет всегда.   

 

 

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

Здравствуйте, помогите разобраться в следующей ситуации, не много не хватает понимания походу.

#include <avr/pgmspace.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27,16,2);

const  char message[ ] PROGMEM = "arduino";
const  char message2[ ] PROGMEM = "hello";
// 
void setup() {
  // put your setup code here, to run once:
	Serial.begin(9600);
	lcd.init();			// Инициализируем дисплей
	lcd.backlight();	// Включаем подсветку экрана
	printMessage(0, 0, message);
	// lcd.setCursor(0, 0);
		// lcd.println(message);	
	
}
void loop() {
  // put your main code here, to run repeatedly:

}

void printMessage(byte Xpos, byte Ypos, char *text){
	lcd.setCursor(Xpos, Ypos);
	char myChar;
	byte len = strlen_P(text);
	for (byte k = 0; k < len; k++){
		myChar =  pgm_read_byte_near(text + k);
		lcd.print(myChar);
	}
} 

Функию printMessage хочу сделать универсальную, что бы ей можно было скармливать любую текстовую константу.

Экономия использования PROGMEM очень заметно, для сообщения "arduino" - экономия ОЗУ - 8 байт.

Но выдаёте ошибку:

sketch_sep15a.ino: In function 'void setup()':
sketch_sep15a.ino:15:28: error: invalid conversion from 'const char*' to 'char*' [-fpermissive]
sketch_sep15a.ino:8:6: error:   initializing argument 3 of 'void printMessage(byte, byte, char*)' [-fpermissive]
Ошибка компиляции.

Убираю * -

void printMessage(byte Xpos, byte Ypos, char text){

получаю обратную ошибку:

sketch_sep15a.ino: In function 'void setup()':
sketch_sep15a.ino:15:28: error: invalid conversion from 'const char*' to 'char' [-fpermissive]
sketch_sep15a.ino:8:6: error:   initializing argument 3 of 'void printMessage(byte, byte, char)' [-fpermissive]
sketch_sep15a.ino: In function 'void printMessage(byte, byte, char)':
sketch_sep15a.ino:28:26: error: invalid conversion from 'char' to 'const char*' [-fpermissive]
In file included from sketch_sep15a.ino:1:0:
c:\program files (x86)\arduino\hardware\tools\avr\avr\include\avr\pgmspace.h:1185:22: error:   initializing argument 1 of 'size_t strlen_P(const char*)' [-fpermissive]
 static inline size_t strlen_P(const char *s) {
                      ^
Ошибка компиляции.
 

Помогите это исправить.

 

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

Давайте, тоже приложу свои 5 копеек. Сообщение об ошибке: "sketch_sep15a.ino:15:28: error: invalid conversion from 'const char*' to 'char' [-fpermissive]"

можно перевести и так: "Инвалид пытается превратить указатель на константу в символьную переменную" .. и эта ошибка практически одинакова как в первой цитате, так и во второй. Вам уже несколько раз отписали, что такое преобразование типов чревато последствиями.. в таком виде и отсутствии понимания - особенно. Что и "беспокоит" компилятор. :)

Указатель на константу - const char* - это НЕИЗМЕННЫЙ указатель. А у вас параметр функции объявлен как char* -- то есть ИЗМЕНЯЕМЫЙ. Вот компилятор и "опасается за инвалида". :) Исправить ситуацию можно объявив параметр константным указателем, типа так:

void printMessage(byte Xpos, byte Ypos, const char *text){

В этом случае, вы объявляете компилятору, что функция НЕ СОБИРАЕТСЯ изменять содержимое и она может принимать как const char*, то есть "строки во флеш"..

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

Arhat109-2, большое спасибо, с указателями пока туго получается, нет практики, а без практики - нет понимания.

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

Жалко что подобные хитрости не описываются для новичков, вот что у меня получилось, а если учесть что в программах бывает очень много текста, то получится очень существенная экономия ОЗУ. Недавно я изучал программирование на андроиде и там все текстовые сообщения и названия были вынесены в отдельные переменные, что помогало легко изменять текст сразу в нескольких местах и упрощало перевод с одного языка на другой. Тут я подумал что это будет лишнем, но не угадал :)

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

#include <avr/pgmspace.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27,16,2);

const  char message[ ] PROGMEM = "arduino";

void setup() {
  // put your setup code here, to run once:
	Serial.begin(9600);
	lcd.init();			// Инициализируем дисплей
	lcd.backlight();	// Включаем подсветку экрана
	/* lcd.setCursor(0, 0);
		lcd.print("arduino"); // заменяем на printMessage()
	*/ 
	printMessage(0, 0, message);
}
void loop() {

}

void printMessage(byte Xpos, byte Ypos, const char *text){
	lcd.setCursor(Xpos, Ypos);
	char myChar;
	byte len = strlen_P(text);
	for (byte k = 0; k < len; k++){
		myChar =  pgm_read_byte_near(text + k);
		lcd.print(myChar);
	}
} 
// Без использования PROGMEM:
// Global variables use 426 bytes (20%) of dynamic memory, leaving 1 622 bytes for local variables. Maximum is 2 048 bytes.

// С использования PROGMEM:
// Global variables use 418 bytes (20%) of dynamic memory, leaving 1 630 bytes for local variables. Maximum is 2 048 bytes.