AS7ti6K

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

81 сообщение в этой теме

AS7ti6K    2

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

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

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 МГц

  • Одобряю 1

Поделиться сообщением


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

Быстрый заказ печатных плат

Полный цикл производства PCB по низким ценам!

  • x
    мм
Заказать Получить купон на $5.00
AS7ti6K    2

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

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

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

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

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

  • Одобряю 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
swat24    9

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
AS7ti6K    2

Спасибо. Разбирался с таймером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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
swat24    9

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
AS7ti6K    2

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

Вопрос 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Alex    494

То, что Вы нашли - моё, и писал я это года наверное 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); Вот и считайте вероятность работоспособности Вашего кода :)

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
AS7ti6K    2

Так нельзя делать. Как только таймер отсчитает, он сразу-же заново запускается при попадании программы в ф-ию 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Alex    494

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
AS7ti6K    2

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

Да, Спасибо.

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Alex    494

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
AS7ti6K    2

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

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
AS7ti6K    2

С учетом статьи из #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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
AS7ti6K    2

Ай нет.... Как всегда рано радуюсь :( Либо опять протеус глючит :crazy:

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
AS7ti6K    2

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

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...

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

Поделиться сообщением


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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
AS7ti6K    2

Когда запускается таймер, Ваша функция возвращает 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
AS7ti6K    2

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Alex    494

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
AS7ti6K    2

Почитайте на тему команды препроцессора - #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 сек.

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Alex    494
а разве не достаточно, что 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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
AS7ti6K    2

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

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

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

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

if(Timer1 > 0) Timer1--;

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

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

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

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

Поделиться сообщением


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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
AS7ti6K    2

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

Декрементироваться это: 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

Поделиться сообщением


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

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

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

Поделиться сообщением


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

Создайте аккаунт или войдите в него для комментирования

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

Создать аккаунт

Зарегистрируйтесь для получения аккаунта. Это просто!

Зарегистрировать аккаунт

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас