Впихнуть невпихуемое

mobistrike
mobistrike аватар
Offline
Зарегистрирован: 19.08.2016

Здравствуйте уважаемые Копперфильды !

Мне снова понадобилась ваша помощь.

Захотелось мне изобрести очень или не очень умный таймер для управлением водонагревателем. Вроде ничего сложного.Начал с написания меню и даже написал.Задача - установить время и дату.  Работает.

НО !!! Заметил и ужаснулся - ведь это фактически четверть меню , а будет еще код управления .

вот 

"Скетч использует 10 108 байт (32%) памяти устройства. Всего доступно 30 720 байт.Глобальные переменные используют 1 508 байт (73%) динамической памяти, оставляя 540 байт для локальных переменных. Максимум: 2 048 байт."

73% памяти съедено ХЗ чем. Ну не совсем ХЗ- библиотеками. 

Вот код

#include <EEPROM.h> // подключаем библиотеку EEPROM
#include <DS1307.h>
#include "lcd1202.h"
#include "ClickButton.h"

LCD1202 lcd(8, 7, 6, 5);  // RST, CS, MOSI, SCK
DS1307 rtc(SDA, SCL);
#define LED 11  // пин светодиода 
const int LBUTTONPIN = 10;
const int RBUTTONPIN = 9;

byte SetTimeH = 0;
byte SetTimeMIN = 0;
byte F_SetTime = 1;
byte F_SetTimeH = 0;
byte F_SetTimeMIN = 0;

byte SetDataDay = 1;
byte SetDataMonth = 1;
byte SetDataGod = 19;
byte F_SetData = 1;
byte F_SetDataDay = 0;
byte F_SetDataMonth = 0;
byte F_SetDataGod = 0;

ClickButton LBUTTON(LBUTTONPIN, LOW, CLICKBTN_PULLUP);
ClickButton RBUTTON(RBUTTONPIN, LOW, CLICKBTN_PULLUP);

void setup()
{
  pinMode(LED, OUTPUT);
  LBUTTON.maxPresses     = 1;    // max button multiclick count
  LBUTTON.debounceTime   = 5;   // Debounce timer in ms
  LBUTTON.multiclickTime = 250;  // Time limit for multi clicks
  LBUTTON.heldDownTime   = 1000; // time until "held-down clicks" register

  lcd.Inicialize();  //Инициализация дисплея
  lcd.Clear_LCD();  //Очистка дисплея

  // Initialize the rtc object
  rtc.begin();
  rtc.setSQWRate(SQW_RATE_1); // Задать частоту на выводе SQW равной 1Гц
  // Set the clock to run-mode
  rtc.halt(false);
  // The following lines can be uncommented to set the time
  //rtc.setDOW(FRIDAY);        // Set Day-of-Week to SUNDAY
  //rtc.setTime(16, 40, 0);     // Set the time to 12:00:00 (24hr format)
  //rtc.setDate(14, 4, 2019);   // Set the date to October 3th, 2010

  //***********************************************************************************************************************
  //rtc.setDate(18, 4, 2019); // Установка даты
  //rtc.setTime(23, 44, 0); // Установка времени
  //*********************************************************************************************************************
  //                         установка время
  //***********************************************************************************************************************
  lcd.print(0, 15, 1, "    ВРЕМЯ ");
  lcd.print(22, 27, 1, rtc.getTimeStr());
  lcd.print(15, 41, 1, "УСТАНОВИТЬ ?");
  lcd.print(0, 60, 0, " да  ");
  lcd.print(65, 60, 0, " нет ");;
  ramka ();
  while (F_SetTime == 1) {
    LBUTTON.Update();
    RBUTTON.Update();
    if (RBUTTON.click == 1) {
      F_SetTime = 0;
    }
    if (LBUTTON.click == 1) {
      F_SetTimeH = 1;
      F_SetTimeMIN = 1;
      F_SetTime = 0;
    }
    lcd.Update();
  }
  lcd.Clear_LCD();
  lcd.Update();
  //***********************************************************************************************************************
  //                         установка время (ЧАСЫ)
  //***********************************************************************************************************************
  ramka ();
  lcd.print(0, 15, 1, "    ВРЕМЯ ");
  lcd.print(22, 27, 1, rtc.getTimeStr());
  lcd.print(0, 60, 0, "  +  ");
  lcd.print(65, 60, 0, " ok  ");;
  lcd.print(45, 46, 1, ":");
  lcd.print(55, 46, 1, SetTimeMIN);
  while (F_SetTimeH == 1) {
    LBUTTON.Update();
    RBUTTON.Update();
    lcd.print(30, 46, 0, SetTimeH);
    lcd.Update();
    if (LBUTTON.click == 1) {  //   установка часов
      digitalWrite(LED, !digitalRead(LED));
      SetTimeH++;
    }
    if (SetTimeH > 23) {
      SetTimeH = 0;
    }
    if (RBUTTON.click == 1) {
      F_SetTimeH = 0 ;
    }
  }
  //***********************************************************************************************************************
  lcd.Clear_LCD();
  lcd.Update();
  //***********************************************************************************************************************
  //                         установка время (МИНУТЫ)
  //***********************************************************************************************************************
  ramka ();
  lcd.print(0, 15, 1, "    ВРЕМЯ ");
  lcd.print(22, 27, 1, rtc.getTimeStr());
  lcd.print(0, 60, 0, "  +  ");
  lcd.print(65, 60, 0, " ok  ");;
  lcd.print(30, 46, 1, SetTimeH);
  lcd.print(45, 46, 1, ":");
  while (F_SetTimeMIN == 1) {
    LBUTTON.Update();
    RBUTTON.Update();
    lcd.print(55, 46, 0, SetTimeMIN);
    lcd.Update();
    if (LBUTTON.click == 1) {  //   установка часов
      digitalWrite(LED, !digitalRead(LED));
      SetTimeMIN++;
    }
    if (SetTimeMIN > 59) {
      SetTimeMIN = 0;
    }
    if (RBUTTON.click == 1) {
      F_SetTimeMIN = 0 ;
    }
    rtc.setTime(SetTimeH, SetTimeMIN, 0); // Установка времени
  }
  lcd.Clear_LCD();
  lcd.Update();
  lcd.print(25, 10, 1,   " ВРЕМЯ");
  lcd.print(15, 22, 1, "УСТАНОВЛЕНО");
  lcd.print(22, 35, 1, rtc.getTimeStr());
  lcd.Update();
  delay (2000);
  //***********************************************************************************************************************
  lcd.Clear_LCD();
  lcd.Update();
  //***********************************************************************************************************************
  //***********************************************************************************************************************
  //                         установка дата
  //***********************************************************************************************************************
  ramka ();
  lcd.print(0, 15, 1, "      ДАТА ");
  lcd.print(22, 27, 1, rtc.getDateStr());
  lcd.print(15, 41, 1, "УСТАНОВИТЬ ?");
  lcd.print(0, 60, 0, " да  ");
  lcd.print(65, 60, 0, " нет ");;

  while (F_SetData == 1) {
    LBUTTON.Update();
    RBUTTON.Update();
    if (RBUTTON.click == 1) {
      F_SetData = 0;
    }
    if (LBUTTON.click == 1) {
      F_SetDataDay = 1;
      F_SetDataMonth = 1;
      F_SetDataGod = 1;
      F_SetData = 0;
    }
    lcd.Update();
  }
  //***********************************************************************************************************************
  lcd.Clear_LCD();
  lcd.Update();
  //***********************************************************************************************************************
  //***********************************************************************************************************************
  //                         установка дата (число)
  //***********************************************************************************************************************
  lcd.print(0, 15, 1, "      ДАТА ");
  ramka ();
  lcd.print(22, 27, 1, rtc.getDateStr());
  lcd.print(0, 60, 0, "  +  ");
  lcd.print(65, 60, 0, " ok  ");;
  lcd.print(10, 46, 1, "Число");
  lcd.print(45, 46, 1, ":");
  while (F_SetDataDay == 1) {
    LBUTTON.Update();
    RBUTTON.Update();
    lcd.print(55, 46, 0, SetDataDay);
    lcd.Update();
    if (LBUTTON.click == 1) {
      digitalWrite(LED, !digitalRead(LED));
      SetDataDay++;
    }
    if (SetDataDay > 31) {
      SetDataDay = 1;
    }
    if (RBUTTON.click == 1) {
      F_SetDataDay = 0 ;
    }
  }
  //***********************************************************************************************************************
  lcd.Clear_LCD();
  lcd.Update();
  //***********************************************************************************************************************
  //                         установка дата (Месяц)
  //***********************************************************************************************************************
  lcd.print(0, 15, 1, "      ДАТА ");
  ramka ();
  lcd.print(22, 27, 1, rtc.getDateStr());
  lcd.print(0, 60, 0, "  +  ");
  lcd.print(65, 60, 0, " ok  ");;
  lcd.print(10, 46, 1, "Месяц");
  lcd.print(45, 46, 1, ":");
  while (F_SetDataMonth == 1) {
    LBUTTON.Update();
    RBUTTON.Update();
    lcd.print(55, 46, 0, SetDataMonth);
    lcd.Update();
    if (LBUTTON.click == 1) {
      digitalWrite(LED, !digitalRead(LED));
      SetDataMonth++;
    }
    if (SetDataMonth > 12) {
      SetDataMonth = 1;
    }
    if (RBUTTON.click == 1) {
      F_SetDataMonth = 0 ;
    }
  }
  //***********************************************************************************************************************
  lcd.Clear_LCD();
  lcd.Update();
  //***********************************************************************************************************************
  //                         установка дата (Год)
  //***********************************************************************************************************************
  lcd.print(0, 15, 1, "      ДАТА ");
  ramka ();
  lcd.print(22, 27, 1, rtc.getDateStr());
  lcd.print(0, 60, 0, "  +  ");
  lcd.print(65, 60, 0, " ok  ");;
  lcd.print(10, 46, 1, "Год");
  lcd.print(45, 46, 1, ":");
  while (F_SetDataGod == 1) {
    LBUTTON.Update();
    RBUTTON.Update();
    lcd.print(55, 46, 0, SetDataGod);
    lcd.Update();
    if (LBUTTON.click == 1) {
      digitalWrite(LED, !digitalRead(LED));
      SetDataGod++;
    }
    if (SetDataGod > 30) {
      SetDataGod = 19;
    }
    if (RBUTTON.click == 1) {
      F_SetDataGod = 0 ;
    }
    rtc.setDate(SetDataDay, SetDataMonth, 2000 + SetDataGod); // Установка даты
  }
  lcd.Clear_LCD();
  lcd.Update();
  lcd.print(25, 10, 1,   " ДАТА");
  lcd.print(15, 22, 1, "УСТАНОВЛЕНА");
  lcd.print(22, 35, 1, rtc.getDateStr());
  lcd.Update();
  delay (2000);
  F_SetTime = 1;
  F_SetTimeH = 0;
  F_SetTimeMIN = 0;
  F_SetData = 1;
  F_SetDataDay = 0;
  F_SetDataMonth = 0;
  F_SetDataGod = 0;
  //***********************************************************************************************************************
  lcd.Clear_LCD();
  lcd.Update();
}
void loop()
{
  lcd.print_1607(0, 1, 1, rtc.getTimeStr());  // печать время
  lcd.print_1607(0, 0, 1, rtc.getDateStr());  // печать дата
  lcd.print_1607(0, 2, 1, rtc.getDOWStr());  // печать день недели
  lcd.Update();
  digitalWrite(LED, !digitalRead(LED));
}
void ramka () {
  // lcd.drawRect(0, 0, 96, 13, 1);    //Рисуем прямоугольник по координатам x, y, высота, ширина, цвет
  //lcd.drawRect(0, 12, 96, 13, 1);    //Рисуем прямоугольник по координатам x, y, высота, ширина, цвет
  lcd.drawRect(0, 24, 96, 13, 1);    //Рисуем прямоугольник по координатам x, y, высота, ширина, цвет
  lcd.print(0, 3, 1, "   НАСТРОЙКА  ");
}

А вот так жрут память библиотеки .Половину памяти !!! Тут так "Скетч использует 3 112 байт (10%) памяти устройства. Всего доступно 30 720 байт.

Глобальные переменные используют 943 байт (46%) динамической памяти, оставляя 1 105 байт для локальных переменных. Максимум: 2 048 байт.
"
#include <EEPROM.h> // подключаем библиотеку EEPROM
#include <DS1307.h>
#include "lcd1202.h"
#include "ClickButton.h"

LCD1202 lcd(8, 7, 6, 5);  // RST, CS, MOSI, SCK
DS1307 rtc(SDA, SCL);
#define LED 11  // пин светодиода 
const int LBUTTONPIN = 10;
const int RBUTTONPIN = 9;

byte SetTimeH = 0;
byte SetTimeMIN = 0;
byte F_SetTime = 1;
byte F_SetTimeH = 0;
byte F_SetTimeMIN = 0;

byte SetDataDay = 1;
byte SetDataMonth = 1;
byte SetDataGod = 19;
byte F_SetData = 1;
byte F_SetDataDay = 0;
byte F_SetDataMonth = 0;
byte F_SetDataGod = 0;

ClickButton LBUTTON(LBUTTONPIN, LOW, CLICKBTN_PULLUP);
ClickButton RBUTTON(RBUTTONPIN, LOW, CLICKBTN_PULLUP);

void setup()
{
  pinMode(LED, OUTPUT);
  LBUTTON.maxPresses     = 1;    // max button multiclick count
  LBUTTON.debounceTime   = 5;   // Debounce timer in ms
  LBUTTON.multiclickTime = 250;  // Time limit for multi clicks
  LBUTTON.heldDownTime   = 1000; // time until "held-down clicks" register

  lcd.Inicialize();  //Инициализация дисплея
  lcd.Clear_LCD();  //Очистка дисплея

  // Initialize the rtc object
  rtc.begin();
  rtc.setSQWRate(SQW_RATE_1); // Задать частоту на выводе SQW равной 1Гц
  // Set the clock to run-mode
  rtc.halt(false);
  // The following lines can be uncommented to set the time
  //rtc.setDOW(FRIDAY);        // Set Day-of-Week to SUNDAY
  //rtc.setTime(16, 40, 0);     // Set the time to 12:00:00 (24hr format)
  //rtc.setDate(14, 4, 2019);   // Set the date to October 3th, 2010

  }
void loop(){
}

Направьте пожалуйста на путь просветления ! Как освободить память ? 

 

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

Начните с макроса F()

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

Как минимум повторяющийся код в функции оформить и вызывать когда нужно вместо того чтобы дублировать

Например это

lcd.print(0, 15, 1, "    ВРЕМЯ ");
lcd.print(22, 27, 1, rtc.getTimeStr());

В это

void printTime(){
   lcd.print(0, 15, 1, "    ВРЕМЯ ");
   lcd.print(22, 27, 1, rtc.getTimeStr());
}

И вызывать в нужном месте

printTime();

Можно весь повторяющийся текст меню сохронить в PROGMEM и читать оттуда (пробелы в тексте тоже память отжирают...)

И т.п.

mobistrike
mobistrike аватар
Offline
Зарегистрирован: 19.08.2016

sadman41 пишет:

Начните с макроса F()

Почитал - пишут "Если в коде используется инструкция вроде...

Serial.print("Write something on the Serial Monitor");

...то выводимая на экран строка, как правило, сохраняется в RAM. Таким образом, если в вашем скетче много подобных строк, которые выводятся на Serial Monitor, то ресурс RAM-памяти может закончиться очень быстро. Однако если у вас есть свободное место во flash-памяти, то вышеуказанную инструкцию можно изменить таким образом, чтобы строка сохранялась именно туда."

Этот номер проходит только с Serial.print ? или везде ?

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

Почти везде.

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

Уточню: в "драйверах", которые написаны авторами, не поленившимися указать родителем своего класса наследника класса Print - работает. В ликвидкристале, например, - всё ок.

mobistrike
mobistrike аватар
Offline
Зарегистрирован: 19.08.2016

Ругается на строку 

lcd.print( F (0, 3, 1, "   НАСТРОЙКА  "));

ошибка "exit status 1

macro "F" passed 4 arguments, but takes just 1"

Как победить ?

 

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

Поставить букву F в правильное место.

Она относится ТОЛЬКО к строке, а не ко всему барахлу, что ещё в программе есть.

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

mobistrike пишет:

Ругается на строку 

lcd.print( F (0, 3, 1, "   НАСТРОЙКА  "));

ошибка "exit status 1

macro "F" passed 4 arguments, but takes just 1"

Как победить ?

 

ты вапще что на этом форуме 3 года делал?  Пошто не ходил на занятия?

mobistrike
mobistrike аватар
Offline
Зарегистрирован: 19.08.2016

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

Поставить букву F в правильное место.

Она относится ТОЛЬКО к строке, а не ко всему барахлу, что ещё в программе есть.

Спасибо !

Так работает

 lcd.print (0, 3, 1,F( "   НАСТРОЙКА  "));

 

mobistrike
mobistrike аватар
Offline
Зарегистрирован: 19.08.2016

DetSimen пишет:

mobistrike пишет:

Ругается на строку 

lcd.print( F (0, 3, 1, "   НАСТРОЙКА  "));

ошибка "exit status 1

macro "F" passed 4 arguments, but takes just 1"

Как победить ?

 

ты вапще что на этом форуме 3 года делал?  Пошто не ходил на занятия?

На занятия я ходил , но только в начальную школу)) 

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

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

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

mobistrike пишет:

НО !!! Заметил и ужаснулся - ведь это фактически четверть меню , а будет еще код управления .

к сожалению, это типично. Та часть кода которая составляет суть и которая будет работать постоянно - занимает 10% программы, а остальные 90% - это меню, которым ты будешь пользоваться от силы 10 минут в месяц

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

mobistrike
mobistrike аватар
Offline
Зарегистрирован: 19.08.2016

b707 пишет:

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

Согласен.Да так бы и сделал если б себе. Устройством будут пользоваться люди далекие от arduin.

mobistrike
mobistrike аватар
Offline
Зарегистрирован: 19.08.2016

Вот что получилось после замены всего "строкового мусора" на F

Скетч использует 8682 байт (28%) памяти устройства. Всего доступно 30720 байт.
Глобальные переменные используют 1054 байт (51%) динамической памяти, оставляя 994 байт для локальных переменных. Максимум: 2048 байт.
Чудеса ! Не зря я вас Копперфильдами назвал ))
Всем спасибо за помощь!
mobistrike
mobistrike аватар
Offline
Зарегистрирован: 19.08.2016

Рано я обрадовался - залил это в arduino . Место надписей пишутся цыфры 

lcd.print(0, 3, 1,F( "   НАСТРОЙКА  "));

Вместо надписи цыфра 104

lcd.print(0, 15, 1, F("    ВРЕМЯ "));

Вместо надписи цыфра 511 

Что не так ?

 

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

Классический случай - нет перегрузки функции под FlashStringHelper*

mobistrike
mobistrike аватар
Offline
Зарегистрирован: 19.08.2016

sadman41 пишет:

Классический случай - нет перегрузки функции под FlashStringHelper*

А можно по-русски ? Ну не программист я . 

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

По-русски для непрограммистов: 

То, что не в F() - при старте переносится в RAM (дублируется), а то что в F() - остаётся лежать в ROM. Методы доступа к данным в RAM и ROM различаются. В своей тайной библиотеке вы имеете только print(), который умеет читать RAM. Для чтения из ROM нужно библиотеку слегонца подрихтовать - задублировать фунцию и добавить пару строк.

mobistrike
mobistrike аватар
Offline
Зарегистрирован: 19.08.2016

sadman41 пишет:

По-русски для непрограммистов: 

То, что не в F() - при старте переносится в RAM (дублируется), а то что в F() - остаётся лежать в ROM. Методы доступа к данным в RAM и ROM различаются. В своей тайной библиотеке вы имеете только print(), который умеет читать RAM. Для чтения из ROM нужно библиотеку слегонца подрихтовать - задублировать фунцию и добавить пару строк.

Спасибо за подробное объяснение ! "библиотеку слегонца подрихтовать" мне не под силу . 

Получается у меня из вариантов 

1. менять библиотеку 

2. менять дисплей 

3. менять ардуину на более "мозговитую"

4. просить Деда Семена написать за меня  бесплатно (он же может )

 

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

Для начала покажите либу. По хидеру будущее не предсказывают.

mobistrike
mobistrike аватар
Offline
Зарегистрирован: 19.08.2016

sadman41 пишет:

Для начала покажите либу. По хидеру будущее не предсказывают.

Тут https://yadi.sk/d/rCJLYdOU6aLQRQ

Green
Offline
Зарегистрирован: 01.10.2015

sadman41 пишет:

По хидеру будущее не предсказывают.

Как то некрасиво, а вас ведь могут читать дети... Правильно хедер.)

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

Раз скрывает библиотеку - значит хидер ;)

mobistrike, напиши мне на wrk.sadman@gmail.com - я скину копипасту. У меня дисплея нет, проверить не могу.

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

mobistrike пишет:

4. просить Деда Семена написать за меня  бесплатно (он же может )

class LCD1202 {
  public:
       LCD1202(uint8_t _RES, uint8_t _CS, uint8_t _Data, uint8_t _Clock);
       void Inicialize();

дальше даже смотреть не стал

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

DetSimen пишет:

class LCD1202 {
  public:
       LCD1202(uint8_t _RES, uint8_t _CS, uint8_t _Data, uint8_t _Clock);
       void Inicialize();

дальше даже смотреть не стал

А чо? Кjнструкция как конструкция - предобъвление функции :))

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

Аптамуш, я какта настороженно отношуся к библиотекам людей, каторые не наследуют класс вывода от Print, и делають ошибки в слове Initialize

mobistrike
mobistrike аватар
Offline
Зарегистрирован: 19.08.2016

DetSimen пишет:

Аптамуш, я какта настороженно отношуся к библиотекам людей, каторые не наследуют класс вывода от Print, и делають ошибки в слове Initialize

Он так видит . 

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

mobistrike пишет:

Он так видит . 

Заработал там грязный хак?

mobistrike
mobistrike аватар
Offline
Зарегистрирован: 19.08.2016

sadman41 пишет:

mobistrike пишет:

Он так видит . 

Заработал там грязный хак?

Почти . Я на почту скинул фотки . Взгляните. 

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

Не тому скинул, наверное.

mobistrike
mobistrike аватар
Offline
Зарегистрирован: 19.08.2016

Выражаю огромную благодарность  sadman41 за помощь в правке библиотеки! После его колдовства все заработало правильно , RAM пока хватает, функция F работает   )) . Если интересно , могу выложить изменения , естественно с разрешения  sadman41

Картинка после второй правки 

Еще раз СПАСИБО !

PS . мыло в 23 посте потри.

 

 

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

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

mobistrike
mobistrike аватар
Offline
Зарегистрирован: 19.08.2016

sadman41 пишет:

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

Ее  бы найти  еще ... Поищу вечером .

ЗЫ. Отписался в той теме.

Иванов1959
Offline
Зарегистрирован: 13.01.2019

mobistrike пишет:

Ее  бы найти  еще ... Поищу вечером .

ЗЫ. Отписался в той теме.

 

Дайте ссылку на этот пост, пожалуйста!

Иванов1959
Offline
Зарегистрирован: 13.01.2019

Дайте ссылку на этот пост, пожалуйста.

mobistrike
mobistrike аватар
Offline
Зарегистрирован: 19.08.2016
mobistrike
mobistrike аватар
Offline
Зарегистрирован: 19.08.2016

Таймер в работе !