Перейти к содержанию

Запись "заводских" настроек в EEPROM AtMega8


-=FISHER=-

Рекомендуемые сообщения

Приветствую всех!

 

Меня интересует вопрос, как правильно записать первоначальные, так сказать "заводские" настройки в EEPROM ? Имею массив структур из двух элементов, каждый из которых хранит в себе информацию о параметрах работы одного из каналов OC1A и OC1B, но не суть. Записываю и читаю данные вот таким способом:

ch chanel[CHANELS_COUNT]; //массив структур для двух каналов

ch EEMEM chanel_ee[CHANELS_COUNT]; //массив структур для двух каналов в EEPROM

//********************************************************************************

eeprom_update_block (&chanel, &chanel_ee, sizeof(chanel)); //запись структуры в EEPROM
	
eeprom_read_block (&chanel, &chanel_ee, sizeof(chanel)); //чтение структуры из EEPROM

Я пробовал так: сначала записываю в коде все исходные параметры в переменные ОЗУ, потом пишу строчку записи структуры из ОЗУ в EEPROM, затем прошиваю МК, запускаю. Все значения попадают в память. Далее убираю из прошивки строчки с записью и оставляю только строчки с чтением из EE (при этом в памяти все значения остаются, проверял считыванием EEPROM). Но вот только когда я запускаю МК с прошивкой без записи в EE, то значения не хотят попадать в ОЗУ!(( То есть не считываются, хотя по факту находятся там, на тех же адресах.

Подскажите пожалуйста, что делаю не так и как правильно?

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

Реклама: ООО ТД Промэлектроника, ИНН: 6659197470, Тел: 8 (800) 1000-321

Когда вы пишите в коде так

//        массив     заводское содержимое  
EEMEM int buf[10] = {0,1,2,3,4,5,6,7,8,9};

и в опциях компилятора (в makefile) включете режим создания файла *.eep, то автоматически будет создан файл с указанным расширением, в котором будет находиться та самая "начальная" или "заводская" информация о содержимом массива, что вы и указали в инициализации. Остается этот файл (это обычный HEX с другим расширением) прошить в EEPROM при программировании МК, и все. Никаких телодвижений более не требуется.

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

20% скидка на весь каталог электронных компонентов в ТМ Электроникс!

Акция "Лето ближе - цены ниже", успей сделать выгодные покупки!

Плюс весь апрель действует скидка 10% по промокоду APREL24 + 15% кэшбэк и бесплатная доставка!

Перейти на страницу акции

Реклама: ООО ТМ ЭЛЕКТРОНИКС, ИНН: 7806548420, info@tmelectronics.ru, +7(812)4094849

1 hour ago, ARV said:

Когда вы пишите в коде так

То есть обязательно заполнять данные во время инциализации, а не в main?

1 hour ago, ARV said:

Никаких телодвижений более не требуется.

А потом соответственно удалить инициализацию переменно в EEPROM? Ведь иначе наверное память при каждом включении будет заполняться "заводскими" настройками?

Оставляя только чтение из EEPROM при включении МК? 

1 hour ago, ARV said:

Когда вы пишите в коде так


//        массив     заводское содержимое  
EEMEM int buf[10] = {0,1,2,3,4,5,6,7,8,9};

А как это выглядеть для массива структур?..

Spoiler

 


typedef struct  //структура для хранения всех свойств канала
{
	unsigned char Delay_TurnOn, //задержка включения
				  Delay_ShutDown, //задержка выключения
				  Bright_Day, //яркость канала днём (при выключенных габаритах)
				  Bright_Night, //яркость канала ночью (при включенных габаритах)
				  Bright_Current, //текущая яркость
				  Bright_Target; //целевая яркость
				  
	unsigned int  Speed_Rise, //скорость розжига канала
				  Speed_Fall, //скорость затухания канала
				  Speed_Gab, //скорость для габаритов
				  Speed_Temp, //временная скорость канала
				  Speed_Target, //целевая скорость канала
				  Speed_Change; //скорость настройки яркости
} ch;

ch chanel[CHANELS_COUNT]; //массив структур для двух каналов в ОЗУ

ch EEMEM chanel_ee[CHANELS_COUNT]; //массив структур для двух каналов в ПЗУ

//***********************************************************************************

	chanel[0].Bright_Current=255; //при инициализации каналы полностью погашены
	chanel[0].Bright_Target=255; //при инициализации каналы полностью погашены
	chanel[0].Bright_Day=60; //(0-255) uint8_t установка дневной яркости 
	chanel[0].Bright_Night=230; //(0-255) uint8_t установка ночной яркости	
	chanel[0].Delay_TurnOn=1; //(0-10) uint8_t установка задержки включения
	chanel[0].Delay_ShutDown=2; //(0-10) uint8_t установка задержки выключения
	chanel[0].Speed_Rise=500; //(0-500) uint16_t  установка скорости розжига
	chanel[0].Speed_Fall=100; //(0-500) uint16_t установка скорости затухания
	chanel[0].Speed_Gab=10; //(0-100) uint8_t установка скорости изменения яркости до габаритов
	chanel[0].Speed_Change=50; //установка скорости розжига	

//********************************* ПАРАМЕТРЫ КАНАЛА 1 ***************************	
 	
	chanel[1].Bright_Current=255; //при инициализации каналы полностью погашены
	chanel[1].Bright_Target=255; //при инициализации каналы полностью погашены	
	chanel[1].Bright_Day=50; //(0-255) установка дневной яркости
	chanel[1].Bright_Night=230; //(0-255) установка ночной яркости
	chanel[1].Delay_TurnOn=4; //(0-10) установка задержки включения
	chanel[1].Delay_ShutDown=2; //(0-10) установка задержки выключения	
	chanel[1].Speed_Rise=500; //(0-500) установка скорости розжига
	chanel[1].Speed_Fall=100; //(0-500) установка скорости затухания
	chanel[1].Speed_Gab=10; //(0-100) установка скорости затухания	
	chanel[1].Speed_Change=50; //установка скорости затухания

 

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

Выбираем схему BMS для заряда литий-железофосфатных (LiFePO4) аккумуляторов

Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

Я использую Atmel Studio 7, и после компиляции, даже без изменения настроек создается файл с расширением *.eep

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

Сравнительное тестирование аккумуляторов EVE Energy и Samsung типоразмера 18650

Инженеры КОМПЭЛ провели сравнительное тестирование аккумуляторов EVE и Samsung популярного для бытовых и индустриальных применений типоразмера 18650. 

Для теста были выбраны аккумуляторы литий-никельмарганцевой системы: по два образца одного наименования каждого производителя – и протестированы на двух значениях тока разряда: 0,5 А и 2,5 А. Испытания проводились в нормальных условиях на электронной нагрузке EBD-USB от ZKEtech, а зарядка осуществлялась от лабораторного источника питания в режиме CC+CV в соответствии с рекомендациями в даташите на определенную модель. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

Just now, -=FISHER=- said:

То есть обязательно заполнять данные во время инциализации, а не в main?

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

Just now, -=FISHER=- said:

А потом соответственно удалить инициализацию переменно в EEPROM? Ведь иначе наверное память при каждом включении будет заполняться "заводскими" настройками?

Память не будет никак заполняться, потому как инициализирующая часть попадает только в файл *.eep и никак не влияет на остальное. Если вы не прошьете этот файл в EEPROM, то в main не увидите никаких данных из этого массива.

Just now, -=FISHER=- said:

А как это выглядеть для массива структур?..

Точно так же, как всегда. Существует 2 способа проинициализировать структуру:

1. указать список значений в фигурных скобках

2. указать списком полей с соответствующими значениями в фигурных скобках.

Соответственно для массива с структур будет список списков :)

typedef struct  //структура для хранения всех свойств канала
{
	unsigned char Delay_TurnOn, //задержка включения
				  Delay_ShutDown, //задержка выключения
				  Bright_Day, //яркость канала днём (при выключенных габаритах)
				  Bright_Night, //яркость канала ночью (при включенных габаритах)
				  Bright_Current, //текущая яркость
				  Bright_Target; //целевая яркость
				  
	unsigned int  Speed_Rise, //скорость розжига канала
				  Speed_Fall, //скорость затухания канала
				  Speed_Gab, //скорость для габаритов
				  Speed_Temp, //временная скорость канала
				  Speed_Target, //целевая скорость канала
				  Speed_Change; //скорость настройки яркости
} ch;
// в структуре всего 12 полей, поэтому можно проинициализировать структуру так:
ch my_struct = {1,2,3,4,5,6,7,8,9,10,11,12};
// при этом надо указывать значения только последовательно по порядку. если указать меньше 12 полей - остальные будут инициализированы нулями
ch my_struct1 = {1,2,3}; // и будет warning

// но более правильно инициализировать поля "поименно", в этом случае можно указывать их в любом порядке, а неуказанные будут обнулены
ch my_struct2 = {.Speed_Target = 10, .Bright_Current = 12};

 

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

Литиевые аккумуляторы EVE Energy и решения для управления перезаряжаемыми источниками тока (материалы вебинара)

Опубликованы материалы вебинара Компэл, посвященного литиевым аккумуляторам EVE Energy и решениям для управления перезаряжаемыми источниками тока.

На вебинаре мы представили информацию не только по линейкам аккумуляторной продукции EVE, но и по решениям для управления ею, что поможет рассмотреть эти ХИТ в качестве дополнительной альтернативы для уже выпускающихся изделий. Также рассмотрели нюансы работы с производителем и сервисы, предоставляемые Компэл по данной продукции. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

2 hours ago, ARV said:

Соответственно для массива с структур будет список списков

Спасибо большое!

2 hours ago, ARV said:

Точно так же, как всегда.

Соответственно, если это массив из двух экземпляров структур, то перечисляем сначала значения 0-го элемента массива, затем первого?

typedef struct  //структура для хранения всех свойств канала
{
	unsigned char Delay_TurnOn, //задержка включения
				  Delay_ShutDown, //задержка выключения
				  Bright_Day, //яркость канала днём (при выключенных габаритах)
				  Bright_Night, //яркость канала ночью (при включенных габаритах)
				  Bright_Current, //текущая яркость
				  Bright_Target; //целевая яркость
				  
	unsigned int  Speed_Rise, //скорость розжига канала
				  Speed_Fall, //скорость затухания канала
				  Speed_Gab, //скорость для габаритов
				  Speed_Temp, //временная скорость канала
				  Speed_Target, //целевая скорость канала
				  Speed_Change; //скорость настройки яркости
} ch;
// в структуре всего 12 полей, поэтому можно проинициализировать структуру так:
ch my_struct[2] = {1,2,3,4,5,6,7,8,9,10,11,12,
                   1,2,3,4,5,6,7,8,9,10,11,12};

 

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

Литиевые батарейки и аккумуляторы от мирового лидера  EVE в Компэл

Компания Компэл, официальный дистрибьютор EVE Energy, бренда №1 по производству химических источников тока (ХИТ) в мире, предлагает продукцию EVE как со склада, так и под заказ. Компания EVE широко известна в странах Европы, Америки и Юго-Восточной Азии уже более 20 лет. Недавно EVE была объявлена поставщиком новых аккумуляторных элементов круглого формата для электрических моделей «нового класса» компании BMW.

Продукция EVE предназначена для самого широкого спектра применений – от бытового до промышленного. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

Каждая структура должна быть в своих скобках.

Массив = {}

Структура = {}

Массив структур = {{},{},{}...}

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

Изменено пользователем ARV

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

@ARV а уже в самой программе оставляю вот такую строку для чтения из EEPROM-массива структур в RAM-массива структур?

eeprom_read_block (&chanel, &chanel_ee, sizeof(chanel));

 

@ARV Заработало!!! Огромное спасибо!!!

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

Да массив и структура - это одно и тоже. Только структуру надо выравнивать (компиляторы разные бывают). А если создать массив структур, то по полям структур можно "скользить" с помощью указателя также, как и по элементам массива.

Ссылка на комментарий
Поделиться на другие сайты

Подскажите ещё пожалуйста, правильно ли я описал включение ножек PB1 и PB2 на выход?

//Пины выходов
#define PIN_CH0OUT _BV(PB1) //выход ШИМ 0-го канала
#define PIN_CH1OUT _BV(PB2) //выход ШИМ 1-го канала

#define OUT_PINS (PIN_CH0OUT|PIN_CH1OUT) //маскируем
  
void port_ini(void)
{
	PORTD|=OUT_PINS; //включаем подтягивающие резисторы на PB1 и PB2
}

 

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

Направление вход-выход задается регистром DDRD

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

1 hour ago, ARV said:

задается регистром DDRD

Опечатался немного

//Пины выходов
#define PIN_CH0OUT _BV(PB1) //выход ШИМ 0-го канала
#define PIN_CH1OUT _BV(PB2) //выход ШИМ 1-го канала

#define OUT_PINS (PIN_CH0OUT|PIN_CH1OUT) //маскируем
  
void port_ini(void)
{
	DDRD|=OUT_PINS; //включаем ножки PB1 и 2 на выход
}

Но в остальном верно?

Изменено пользователем -=FISHER=-

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

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

1. Имеется две кнопки, одна для 1-го канала, другая для 2-го;

(Далее пример реакций на нажатие для одной кнопки, для второй всё аналогично, только номер канала меняется).

2. Нажимая на кнопку первый раз и удерживая, начинает расти яркость канала;

3. Отпустив кнопку и нажав её повторно и удерживая начинает уменьшаться яркость канала;

4. Если яркость упрется в 0 или 255, канал начинает моргать, показывая что достигнуто критическое значение;

5. Есть режим яркости для выключенных габаритов и для включенных, какой из них включен на данный момент, определяется по содержанию переменной button_state, которое может равняться 1 или 0.

@ARV Было бы интересно услышать Ваш подход с методами нисходящего программирования.

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

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

В чем, собственно, у вас проблема? Алгоритм редактирования яркости при помощи кнопок вы описали вполне понятно. Если проблема в реализации мигания для "упора", то оно делается элементарно путем накладывания "маски" на яркость по таймеру. Когда уперлись в край, активируете таймер при нажатой кнопке (а при отжатой - деактивируете). Таймер этот при срабатывании XOR-ит текущую яркость с 0xFF и с 0x00 поочередно каждый свой тик, что в итоге дает нужное вам мерцание.

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

1 hour ago, ARV said:

В чем, собственно, у вас проблема?

У меня просто в голове крутится конструкция с множеством IF-ELSE, мне почему-то кажется это неправильным. Я вечером распишу как я это представляю и скину сюда.

 

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

Я не спрашивал про то, что крутится в голове - это у вас крутится вариант РЕШЕНИЯ проблемы. Я спрашивал о самой проблеме - в чем она заключается? Что решать-то надо?

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

4 hours ago, ARV said:

Что решать-то надо?

Нужно распутать клубок if-else...

Вот смотрите, прежде чем изменить яркость мне нужно проверить аж 4 параметра, это всё у меня получаются вложенные if-else. Допустим я отловил нажатие первой кнопки (пример для 0-го канала):

1. Разрешено ли изменение яркости? (То есть "протикал" ли таймер нужный отрезок времени чтобы яркость плавно изменялась, а не мгновенно);

2. Какое направление изменения яркости (наращивать или убавлять яркость?);

3. Включены габариты или нет? (Чтобы понимать дневной или ночной параметр мы регулируем) (input_state == GAB_ON) или (input_state == GAB_OFF);

4. Яркость уже достигла минимума или максимума? (Чтобы морганием сигнализировать о достижении предела).

И только потом будет ясно, какой из вариантов действий выбрать:

chanel[0].BrightDay++;

chanel[0].BrightDay--;

chanel[0].BrightNight++;

chanel[0].BrightNight--;

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

Не знаю, что у вас за клубок...

Вопросы изменения яркости человеком и её фактическая "отработка" контроллером - две не связанные ветки. Человек меняет яркость не когда разрешено, а когда хочет, а уж МК отрабатывает это "плавно" или как-то иначе. Поэтому в обработке кнопок никаких проверок "можно или нет"не требуется - можно всегда.

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

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

Изменено пользователем ARV

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

1 hour ago, ARV said:

Далее, направление изменения у вас всегда меняется на противоположное в момент отпускания кнопки - так?

Да, именно так и планировал, но вот дальше.

1 hour ago, ARV said:

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

А если я не буду его анализировать явно, типа: if(dir==0){прибавляем яркость;} if(dir==1){убавляем яркость}

То как же МК поймет когда прибавлять, а когда убавлять?...

1 hour ago, ARV said:

И только достижение "края" есть смысл отслеживать постоянно. Поскольку процесс изменения одинаков для всех 4-х яркостей, есть смысл делать это при помощи функции, получающей указатель на нужную яркость

Процесс изменения одинаков, если брать во внимание количество каналов, для всех 8 яркостей, поэтому универсальная функция бы здесь не помешала...

1 hour ago, ARV said:

Вопросы изменения яркости человеком и её фактическая "отработка" контроллером - две не связанные ветки.

Да, но если изменение яркости (инкремент Bright++) будет происходить каждый раз, когда программа будет отслеживать нажатие кнопки - неправильно, потому что светодиод вспыхнет на полную яркость за доли секунды. Вот поэтому я написал что нужно как бы разрешение (наверное это не самый рациональный подход, но концепция ведь верная?) на изменение яркости, которое будет выдаваться, предположим, каждые 100 мс.

@ARV Спасибо что отвечаете:)

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

4 minutes ago, -=FISHER=- said:

То как же МК поймет когда прибавлять, а когда убавлять?...

Слыхали про такое - число со знаком? ;) 

int direction;

bright += direction;

Если direction = 1, то яркость увеличится, если direction = -1, то уменьшится.

8 minutes ago, -=FISHER=- said:

нужно как бы разрешение (наверное это не самый рациональный подход, но концепция ведь верная?) на изменение яркости, которое будет выдаваться, предположим, каждые 100 мс.

Если информация о нажатии кнопки будет поступать каждые 100 мс, то никаких разрешений не потребуется.

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

1 hour ago, ARV said:

Если direction = 1, то яркость увеличится, если direction = -1, то уменьшится.

Это гениально!))

1 hour ago, ARV said:

Если информация о нажатии кнопки будет поступать каждые 100 мс, то никаких разрешений не потребуется.

То есть достаточно просто опрашивать кнопку раз в 100 мс ?? Это проще чем я думал! Значит опрос кнопки нужно проводить в прерывании таймера, откалиброванным на 100 мс.

1 hour ago, ARV said:

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

А можете рассказать, хотя бы в общих чертах, что имеется ввиду под хитрым способом с Вашей колокольни?

Мы все учились по-немногу, чему-нибудь и как-нибудь...

Ссылка на комментарий
Поделиться на другие сайты

Моя колокольня в том, что я, не зная общей архитектуры вашей программы, все неизвестное сразу представляю, как будто я его сам сделал. Ну типа как в том анекдоте "я три дня не ел - ну, так нельзя, надо себя заставлять". И мои советы могут быть, мягко говоря, не в струю.

Изменено пользователем ARV

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.
Примечание: Ваш пост будет проверен модератором, прежде чем станет видимым.

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить в этой теме...

×   Вставлено с форматированием.   Восстановить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

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

Загрузка...
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу

×
×
  • Создать...