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

Расчет Времени Цикла


AS7ti6K

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

Подскажите как правильно рассчитать или как это делается - вот что:

Есть такой цикл:

for (unsigned char N = 1; N < 6; N++) {
 ......
 while (тут нужно подождать от 1 сек до 6 сек) if (PORTAbits.RA0 || PORTAbits.RA1) break;
 .......
 while (тут нужно подождать от 1 сек до 6 сек) if (PORTAbits.RA0 || PORTAbits.RA1) break;
}

Цикл выполняется, там есть какие-то действия, и вот в некоторых местах нужно сделать паузы, например по 3 секунды, но очень важна постоянно проверка портов. Как рассчитать продолжительность цикла?

МК PIC16F630 с внутренним тактовым генератором 4 МГц

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

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

Экспериментирую....

вот вроде бы вот такой код:

for (unsigned long int K = 0; K<1000000; K++) if (PORTAbits.RA0 || PORTAbits.RA1) break;

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

Протеус врет или как-то не так я эти задержки делаю.?

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

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

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

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

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

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

for (unsigned long int K = 0; K<1000000; K++)
if (PORTAbits.RA0 || PORTAbits.RA1) 
break;

У Вас в цикле стоит проверка условия. Эта проверка условия сколько команд занимает? Я бы сделал по счетчику. Расчитать делитель, значения для загрузки в счетный регистр и включить прерывание с таймером. По прерыванию устанавливать/сбрасывать флаг. А код примет вид:

while (!flag)
  {
  if (PORTAbits.RA0 || PORTAbits.RA1) 
     {
      break;
     }
  }

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

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

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

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

Спасибо. Разбирался с таймером1... В интернете наткнулся на каком-то форуме на пример от Alexa

Я его немного модернезировал.

Вот что получилось:

#include
#include
#include

// CONFIG
#pragma config FOSC = INTRCIO // Oscillator Selection bits (INTOSC oscillator: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF // RA3/MCLR pin function select (RA3/MCLR pin function is digital I/O, MCLR internally tied to VDD)
#pragma config BOREN = OFF // Brown-out Detect Enable bit (BOD disabled)
#pragma config CP = OFF // Code Protection bit (Program Memory code protection is disabled)
#pragma config CPD = OFF // Data Code Protection bit (Data memory code protection is disabled)

//static volatile near unsigned int TMR1 @ 0x00E; //Уже объявлена в pic16f630.h

//****************************** Таймер 1*******************//
struct {
unsigned enabled : 1; // таймер вкл./выкл.
unsigned int interval; // текущее значение таймера
} Timer1;

void Timer1_modal(void) {
if(Timer1.enabled) { // если таймер включен
Timer1.interval--; // уменьшаем его значение на еденицу
if(!Timer1.interval) Timer1.enabled=0; // если таймер дошёл до нуля, выключаем его
}
}
//*******************************************************//
void interrupt isr(void) {
if(TMR1IF){
TMR1IF =0;
TMR1= 65537 - 1000 + TMR1;
Timer1_modal();
}
}
//*******************************************************//

//*******************************************************//
void main() {
CMCON = 0x07;
PORTA = 0;
PORTC = 0;
TRISA = 0b00000001;
TRISC = 0b00000000;

TMR1IF=0;
TMR1ON=1;
TMR1= 65535 - 1000; // Таймер на 1000 циклов
TMR1IE=1;

PEIE=1;
GIE=1;

while(1) {
Timer1.interval=1000;
Timer1.enabled=1;
while(Timer1.enabled) if (PORTAbits.RA0) {
Timer1.enabled = 0;
break;
}
PORTCbits.RC2 = !PORTCbits.RC2;
while (PORTAbits.RA0);
}
}
//*******************************************************//

Код работает. ...наверное правильно, но не уверен. Отсюда у меня пара вопросов

Вопрос 1

Так как из отладчиков у меня только протеус пока. По другому не умею а аппаратных нет

Собс-но вопрос: Почему в протеусе на порту PORTCbits.RC2 (там светодиод) моргает как-то "не ровно" т.е. не четко через 1 сек.?

Оценку равномерности моргания делал "на глаз"... Опять же повторяюсь - это протеус так себя ведет, т.е. это его фича или что?

Вопрос 2

Вот это:

void Timer1_modal(void) {
if(Timer1.enabled) { // если таймер включен
Timer1.interval--; // уменьшаем его значение на еденицу
if(!Timer1.interval) Timer1.enabled=0; // если таймер дошёл до нуля, выключаем его
}
}
//*******************************************************//
void interrupt isr(void) {
if(TMR1IF){
TMR1IF =0;
TMR1= 65537 - 1000 + TMR1;
Timer1_modal(); // <--- Отдельная функция
}
}

Не тоже самое, что ниже?

void interrupt isr(void) {
if(TMR1IF){
TMR1IF =0;
TMR1= 65537 - 1000 + TMR1;
[b]if(Timer1.enabled) { // если таймер включен
Timer1.interval--; // уменьшаем его значение на еденицу
if(!Timer1.interval) Timer1.enabled=0; // если таймер дошёл до нуля, выключаем его[/b]
ms++;
if(ms>999){
ms=0;
NOP(); // 1 секунда
}
}
}

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

Что-то Тэг

 как-то все форматирование кода нарушает 
Изменено пользователем AS7ti6K
Ссылка на комментарий
Поделиться на другие сайты

У меня к двум вопросам еще один добавился, прошу, знающие ответьте

Вопрос 3

Почему после изменения вот этого куска кода:

void main() {
....
 while(1) {
   Timer1.interval=1500;
   Timer1.enabled=1;
   while(Timer1.enabled)
     if (PORTAbits.RA0) {
       Timer1.enabled = false;
       break;
     }
   PORTCbits.RC2 = !PORTCbits.RC2;
   while (PORTAbits.RA0);
 }
}

на такой

bool RunTMR1 (unsigned int ms) {
 if (!Timer1.enabled){
   Timer1.interval = ms;
   Timer1.enabled = true;
 }
 return (Timer1.enabled);
}

void main() {
....
 while(1) {
   while(RunTMR1(1500))
     if (PORTAbits.RA0) {
       Timer1.enabled = false;
       break;
   }
   PORTCbits.RC2 = !PORTCbits.RC2;
   while (PORTAbits.RA0);
 }
}

Программа в протеусе начинает работать по другому

Т.е. в первом случае светодиод начинает сразу после запуска (нажатия на треугольник в протеусе) моргать с периодичностью ~1 сек.

А во втором - сразу после запуска пауза секунд 10-12, а затем начинает моргать как и в первом случае

Что это может быть?

в чем пишите? и если можно выложите проект для протеуса.

Пишу в MPLAB X компилятор XC8

_TMR1.zip

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

То, что Вы нашли - моё, и писал я это года наверное 3-4 назад. Сейчас даже не помню где и когда...

Вот ещё статейка, почитайте - http://forum.chipmk....аммные-таймеры/

bool RunTMR1 (unsigned int ms) {
if (!Timer1.enabled){
 Timer1.interval = ms;
 Timer1.enabled = true;
}
return (Timer1.enabled);
}

.............
.............

while(RunTMR1(1500)){
....
}

Так нельзя делать. Как только таймер отсчитает, он сразу-же заново запускается при попадании программы в ф-ию RunTMR1. И Вам повезёт только тогда, когда бит .enabled сменит своё состояние между условием if (!Timer1.enabled) и return (Timer1.enabled); Вот и считайте вероятность работоспособности Вашего кода :)

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

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

Так нельзя делать. Как только таймер отсчитает, он сразу-же заново запускается при попадании программы в ф-ию RunTMR1. И Вам повезёт только тогда, когда бит .enabled сменит своё состояние между условием if (!Timer1.enabled) и return (Timer1.enabled); Вот и считайте вероятность работоспособности Вашего кода :)

Спасибо. Вроде немного понимаю, ну а если тогда вот так переделать функцию RunTMR1:

bool RunTMR1 (unsigned int ms) {
bool F;
 F = Timer1.enabled;
 if (!F){
   Timer1.interval = ms;
   Timer1.enabled = true;
 }
 return (F);
}

ну и вызов тот же

while(RunTMR1(1000))

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

Я бы не спрашивал, если бы в протеусе было все четко, а тут с данным кодом диод моргает тоже как-то не равномерно, впрочем как не равномерно моргает и с вашим вариантом:

Timer1.interval=1000;
Timer1.enabled=1;
while(Timer1.enabled)

Т.е. теперь мой и Ваш вариант работают примерно одинаково.

У меня нет пока возможности проверить в железе, но по протеусу по этому поводу пока никто не ответил..... может я и зря кипишую :)

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

Понятно, полностью согласен :)

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

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

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

ЗЫ: Кстати, Вы статью почитали по ссылке ? Там попроще немного вариант с таймерами.

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

ЗЫ: Кстати, Вы статью почитали по ссылке ? Там попроще немного вариант с таймерами.

Да, Спасибо.

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

Сейчас проект выложу...

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

Если у Вас эти примеры не работают, значит какие-то проблемы с протеусом, т.к. они проверены.

Хм.... странно сейчас сделал копию папки с проектом, ну чтобы почистить папку и сделать архив вот этот: _TMR1.zip

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

Странно.... Перезапустил всё, перепроверил.... вроде сейчас моргает более менее равномерно....

Ну так как на счет RunTMR1 - нормальный вариант? :)

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

С учетом статьи из #7

сделал так:

#include <stdbool.h>
#include <xc.h>
// CONFIG
#pragma config FOSC = INTRCIO // Oscillator Selection bits (INTOSC oscillator: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN)
#pragma config WDTE = OFF	 // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF	 // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF	 // RA3/MCLR pin function select (RA3/MCLR pin function is digital I/O, MCLR internally tied to VDD)
#pragma config BOREN = OFF	 // Brown-out Detect Enable bit (BOD disabled)
#pragma config CP = OFF		 // Code Protection bit (Program Memory code protection is disabled)
#pragma config CPD = OFF	 // Data Code Protection bit (Data memory code protection is disabled)

//****************************** Таймер 1*******************//
volatile signed int Timer1;
void interrupt isr(void) {
 if(TMR1IF){
   TMR1IF =0;
   TMR1= 65537 - 1000 + TMR1;
   if(Timer1 < 0) Timer1++; // Если таймер запущен уменьшаем его счётчик на единицу.
 }
}
//*******************************************************//
bool RunTMR1 (unsigned int ms) {
bool F;
 F = Timer1<0;
 if(Timer1 >= 0) Timer1 = -ms;
 return (F);
}
//*******************************************************//
void main() {
 CMCON = 0x07;
 PORTA = 0;
 PORTC = 0;
 TRISA = 0b00000001;
 TRISC = 0b00000000;
 TMR1ON=1;
 TMR1IF=0;
 TMR1= 65535 - 1000; // Таймер на 1000 циклов
 TMR1IE=1;
 PEIE=1;
 GIE=1;
 while(1) {
   while(RunTMR1(500))
     if (PORTAbits.RA0) {
       Timer1 = 0;
       break;
     }
   PORTCbits.RC5 = !PORTCbits.RC5;
   while (PORTAbits.RA0);
 }
}
//*******************************************************//

Что скажете?

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

Что-то не пойму почему:

bool RunTMR1 (unsigned int ms) {
bool F;
F = Timer1 < 0;
if(Timer1 >= 0) Timer1 = -ms;
return (F);
}

и

while RunTMR1(1000) 

НЕ работает, т.е. работает не правильно, а это:

Timer1=-1000;
while (Timer1<0)

работает вроде нормально?

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

Что-то никак не поймаю суть :( Наверное неделя изучения Си - мало :)

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

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

Вы не в правильном направлении...

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

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

Хм... вроде понимаю.

Останавлюсь всеж на Вашем варианте:

#include <stdbool.h>
#include <xc.h>
// CONFIG
#pragma config FOSC = INTRCIO   // Oscillator Selection bits (INTOSC oscillator: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN)
#pragma config WDTE = OFF	   // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF	  // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF	  // RA3/MCLR pin function select (RA3/MCLR pin function is digital I/O, MCLR internally tied to VDD)
#pragma config BOREN = OFF	  // Brown-out Detect Enable bit (BOD disabled)
#pragma config CP = OFF		 // Code Protection bit (Program Memory code protection is disabled)
#pragma config CPD = OFF	    // Data Code Protection bit (Data memory code protection is disabled)
//static volatile near unsigned int TMR1  @ 0x00E; //Уже объявлена в pic16f630.h
//****************************** Таймер 1*******************//
volatile unsigned int Timer1;
void interrupt isr(void) {
 if(TMR1IF){
   TMR1IF = 0;
   TMR1= 65537 - 1000 + TMR1;
   if(Timer1 > 0) Timer1--;	  // Если таймер запущен уменьшаем его счётчик на единицу.
 }
}
//*******************************************************//
//*******************************************************//
void main() {
 CMCON = 0x07;
 PORTA = 0;
 PORTC = 0;
 TRISA = 0b00000001;
 TRISC = 0b00000000;
 TMR1ON = 1;
 TMR1IF = 0;
 TMR1 = 65535 - 1000;   // Таймер на 1000 циклов
 TMR1IE = 1;
 PEIE = 1;
 GIE = 1;

 while(1) {
   Timer1=1000;
   while (Timer1 > 0)
  if (PORTAbits.RA0) {
    Timer1 = 0;
    break;
  }
   PORTCbits.RC5 = !PORTCbits.RC5;
   while (PORTAbits.RA0);
 }
}
//*******************************************************//

Единственное только поменял - на + в счетчике.... ну так как-то логичнее.

Alex, Спасибо большое за терпеливые разъяснения. Я иногда туплю..... пока не докопаюсь до истины :)

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

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

А можно немного подробнее? Или не стоит заморачиваться и оставить как есть...

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

Почитайте на тему команды препроцессора - #define

Единственное только поменял - на + в счетчике.... ну так как-то логичнее.
Ни капельки не логичней. Смысл в том, что старший бит являлся флагом. А сейчас этого нет...

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

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

Почитайте на тему команды препроцессора - #define

Ок.

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

а разве не достаточно, что Timer1 > 0 (= true) а Timer1==0 (=ложь) уже флаг?

т.е. код можно сократить до такого:

volatile unsigned int Timer1;
void interrupt isr(void) {
 if(TMR1IF){
   TMR1IF = 0;
   TMR1= 65537 - 1000 + TMR1;
   if(Timer1) Timer1--;	  // Если таймер запущен уменьшаем его счётчик на единицу.
 }
}
void main() {
....... 
 while(1) {
   Timer1 = 1000;
   while (Timer1)
  if (PORTAbits.RA0) {
    Timer1 = 0;
    break;
  }
   PORTCbits.RC5 = !PORTCbits.RC5;
   while (PORTAbits.RA0);
 }
}

И он работает, только почему-то не совсем точно тикает, но так же не точно и с минусом.... скорее всего это протеус парится.

Т.е. если выставлять таймер на 1 сек (Timer1=1000) то этого не заметно, но если выставить таймер на 10 сек (Timer1 = 10000) то диод мигает где-то с переодичностью 12-13 сек.

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

Ну я же учусь.... :) Вы меня только поймите правильно

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

а разве не достаточно, что Timer1 > 0 (= true) а Timer1==0 (=ложь) уже флаг?
Достаточно, но не атомарно. При проверке на отрицательность, проверяется всего один старший бит, а битовые операции всегда атомарны.

Да и код получается больше. Проверка одного бита - 1 команда, а проверка 2-ухбайтной переменной на ноль - минимум 3 (зависит от оптимизации).

  if(Timer1) Timer1--; // Если таймер запущен уменьшаем его счётчик на единицу.
047 0824 MOVF 0x24, W
048 0423 IORWF Timer1, W
049 1903 BTFSC STATUS, 0x2
04A 2851 GOTO 0x51
04B 3001 MOVLW 0x1
04C 02A3 SUBWF Timer1, F
04D 3000 MOVLW 0
04E 1C03 BTFSS STATUS, 0
04F 03A4 DECF 0x24, F
050 02A4 SUBWF 0x24, F

и

  if(Timer1<0) Timer1++; // Если таймер запущен уменьшаем его счётчик на единицу.
047 1FA4 BTFSS 0x24, 0x7
048 284C GOTO 0x4c
049 0AA3 INCF Timer1, F
04A 1903 BTFSC STATUS, 0x2
04B 0AA4 INCF 0x24, F

Разницу чувствуете ? :)

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

Разницу чувствуете ? :)

Н... да.... Я в ассемблере, конечно, вообще не понимаю, но визуально да, кода меньше....

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

А если так сделать:

if(Timer1 > 0) Timer1--;

Здесь не знак проверяется?

Как в МПЛАБе посмотреть ассемблерный код?

Т.е. в принципе это только на оптимизацию влияет, на скорость выполнения программы и ее общий размер в МК. Так?

Тогда это веские моменты..... нужно учить...

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

Как в МПЛАБе посмотреть ассемблерный код?
View->Disassembly Listing
Здесь не знак проверяется?
Знак. Но при нулевом значении, переменная будет декрементироваться. А это не есть правильно :)
В Делфи даже не заморачивался особо по таким поводам.
Отсюда и все проблемы, как обычно. Не зря советуют начинать программирование с низкого уровня, дабы знать все нюансы. МК - это далеко не ПК.
Т.е. в принципе это только на оптимизацию влияет, на скорость выполнения программы и ее общий размер в МК. Так?
Не только. Нужно ещё не забывать про атомарность, когда работаешь параллельно (в нашем случае - прерывание и основной цикл) с объектами. Ошибка с атомарным доступом может сыграть очень злую шутку, причём подобные косяки очень трудно вылавливаются.
Ссылка на комментарий
Поделиться на другие сайты

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

Декрементироваться это: DEC(X) или X=X-1 или X--

да?

Тогда где тут

if(Timer1 > 0) Timer1--;

это?

Когда Timer1 будет равен 0 Timer1-- перестанет выполнятся.... Или я опять что-то не так понял :(

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

Согласен на все 100.... Эх вернуть бы лет 15 назад я бы си теперь выбрал :) А ведь выбирал си либо Delphi 1(Object Pascal) еще был)

атомарность

Пошел искать что это за матное слово :)

View->Disassembly Listing - что-то нет такого :( MPLAB X v1.90

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

Когда Timer1 будет равен 0 Timer1-- перестанет выполнятся.... Или я опять что-то не так понял
А, ну да вообщето, тупанул я немного... Будет уменьшаться только когда переменная больше нуля.

Но тут нужно посмотреть, как компилятор проверяет это условие.

Пошел искать что это за матное слово
Обязательно почитайте на эту тему, и постарайтесь её понять как можно лучше. Будут вопросы - задавайте.
View->Disassembly Listing - что-то нет такого MPLAB X v1.90
В MPLAB X я сам не нашёл где просматривается дизасм. Вообще он мне не понравился - одни тормоза и никаких плюсов относительно обычного МПЛАБа.
Ссылка на комментарий
Поделиться на другие сайты

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

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

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

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

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

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

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

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

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

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

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