При работе с Arduino иногда возникает необходимость вывести какие-либо данные на дисплей, но передавать для этого данные на ПК имеет смысл только если устройство будет использоваться в связке с ПК. А как же быть с автономными устройствами? Тут на помощь придут LCD-дисплеи.
Рассмотрим LCD-дисплеи на базе контроллера HD44780 на примере WH1602B-YYK-CTK.
Этот монохромный дисплей имеет опциональную подсветку и может отображать 2 строки по 16 символов. Разрешение символов — 5x8 точек. Есть поддержка кириллицы, но странная, об этом — в конце статьи.
Чем хороши такие дисплеи? Контроллер HD44780 — стандарт де-факто среди небольших монохромных LCD-дисплеев, поэтому библиотеку для работы с дисплеями на его базе не написал только ленивый. Ленивым на сей раз оказался я, а вот разработчики Arduino написали библиотеку для своей платформы, и называется она LiquidCrystal. Её мы и используем для работы с выбранным мной дисплеем.
Итак, прежде чем писать код, нужно подключить дисплей к Arduino. Вам понадобятся:
или
LCD-дисплей, например WH1602B-YYK-CTK
макетная плата
соединительные провода
потенциометр
Схема подключения в официальном руководстве на сайте Arduino выглядит так:
Однако, здесь по какой-то причине не используется подсветка, без которой изображение на дисплее выглядит хуже, чем на дешёвых китайских электронных часах. Так что мы, как подобает настоящим джедаям, её задействуем.
Кстати, дисплей имеет режим самотестирования, который можно включить, подсоединив выводы:
1 — Vss, земля ⇨ GND
2 — Vdd, питание ⇨ +5 В
3 — Vo, управление контрастностью напряжением ⇨ выход потенциометра
15 — A, питание для подсветки ⇨ +5 В
16 — K, земля для подсветки ⇨ GND
Верхний ряд символов должен полностью заполниться тёмными прямоугольниками:
Повращайте ручку потенциометра, чтобы настроить контрастность дисплея. Если вы не видите верхний ряд прямоугольников, то либо вы неправильно подключили дисплей, либо его сожгли.
Хотя, кто знает — может, просто режим самотестирования не поддерживается (:
А для полноценной работы с дисплеем подключим 12 выводов:
1 — Vss, земля ⇨ GND
2 — Vdd, питание ⇨ +5 В
3 — Vo, управление контрастностью напряжением ⇨ выход потенциометра
4 — RS, выбор регистра ⇨ пин 12 Arduino
5 — R/W, чтение/запись ⇨ земля (режим записи)
6 — E, он же Enable, cтроб по спаду ⇨ пин 11 Arduino
7-10 — DB0-DB3, младшие биты 8-битного интерфейса; не подключены
Этот дисплей, как и прочие на контроллере HD44780, поддерживает два варианта параллельного интерфейса:
8-битный, выводы DB0-DB7, за один такт передаётся 1 байт (8 бит)
4-битный, выводы DB4-DB7, за один такт передаётся половина байта (4 бита)
Смысла использовать 8-битный вариант нет, потому что это требует больше ног, а выигрыша в скорости всё равно нет: частота обновления дисплея не больше 10 раз в секунду, так что мы всё равно не сможем увидеть часто обновляемые данные. Поэтому выводы DB0-DB3 оставляем неподключенными.
Ну что же, всё подключено — пора писать код. Начнём с классического «Hello, World», который доступен в Arduino IDE через пункт меню File ⇨ Examples ⇨ LiquidCrystal ⇨ HelloWorld:
/* Подключаем библиотеку для работы с LCD */
#include <LiquidCrystal.h>
/* Создаём объект LCD-дисплея, используя конструктор класса LiquidCrystal
* с 6ю аргументами. Библиотека по количеству аргументов сама определит,
* что нужно использовать 4-битный интерфейс.
* Указываем, к каким пинам Arduino подключены выводы дисплея:
* RS, E, DB4, DB5, DB6, DB7
*/
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
void setup()
{
/* Инициализируем дисплей: 2 строки по 16 символов */
lcd.begin(16, 2);
/* Выводим на дисплей традиционную фразу (: */
lcd.print("hello, world!");
}
void loop()
{
/* Устанавливаем курсор в 1 столбец 2й строки. Нумерация идёт с нуля,
* первым аргументом идёт номер столбца.
*/
lcd.setCursor(0, 1);
/* Выводим на дисплей число секунд, прошедших с момента старта Arduino */
lcd.print(millis() / 1000);
}
Ничего сложного, как видите: основного кода набралось всего 4 строки.
Обратите внимание на инициализацию дисплея:
lcd.begin(16, 2);
Здесь мы задали размер экрана: 2 строки по 16 символов. Прелесть в том, что можно, ничего не меняя в схеме, подцепить другой дисплей — например, размером 16х4 символа, или сэкономить и взять 8х2. Достаточно изменить строку инициализации соответственно размеру подключенного дисплея.
Но банальными надписями сыт не будешь, так что изучим документацию на предмет более продвинутых возможностей. Нам доступные следующие полезные методы:
home() и clear()
Первый метод возвращает курсор в начало экрана; clear() делает то же самое, заодно стирая всё, что было на дисплее до этого.
write(ch)
Выводит одиночный символ ch на дисплей.
Пример:
lcd.write('z');
lcd.write(0); // вывести символ с кодом 0; см. метод createChar()
cursor() и noCursor()
Позволяют показать курсор на дисплее (символ подчёркивания) и скрыть его.
blink() и noBlink()
Включить и выключить мигание курсора, если включено его отображение.
display() и noDisplay()
Включить и выключить дисплей.
scrollDisplayLeft() и scrollDisplayRight()
Прокрутить экран на один символ влево или вправо.
autoscroll() и noAutoscroll()
Включить и выключить режим автопрокрутки. В этом режиме при выводе каждого следующего символа содержимое экрана будет смещено на один символ влево (или вправо, если включен режим вывода справа налево), а выводимый символ займёт место первого сдвинутого. Проще говоря, в этом режиме все последующие символы выводятся в одно и то же место, вытесняя текущее содержимое экрана.
leftToRight() и rightToLeft()
Устанавливают направление вывода текста: слева направо и справа налево, соответственно.
createChar(ch, bitmap)
Самая крутая функция: позволяет создать свой символ с кодом ch (от 0 до 7), пользуясь массивом битовых масок bitmap для задания тёмных и светлых точек.
Неплохо бы опробовать все эти функции, не правда ли? Сказано — сделано! Напишем большой и фаршированный функционалом скетч:
#include <LiquidCrystal.h>
/* Константа: высота символа в точках */
enum { SYMBOL_HEIGHT = 8 };
/* Описываем наши собственные символы в виде массивов битовых масок.
* Каждый символ - это восемь масок по пять бит.
*/
byte arnie[SYMBOL_HEIGHT] =
{
B10101,
B11111,
B10111,
B11111,
B11111,
B00111,
B11110,
B00000,
};
byte skull_and_bones[SYMBOL_HEIGHT] =
{
B01110,
B10101,
B11011,
B01110,
B00000,
B10001,
B01110,
B10001,
};
byte lightning[SYMBOL_HEIGHT] =
{
B00010,
B00100,
B01000,
B11111,
B00010,
B00100,
B01000,
B00000,
};
/* Константы размеров экрана. Нужны для того, чтобы размер экрана
* менять только в одном месте, а не по всему коду. Везде, где
* результат вывода на дисплей должен зависеть от размера экрана,
* следует использовать эти константы.
*/
enum { LCD_WIDTH = 16, LCD_HEIGHT = 2 };
/* Объявляем объект нашего дисплея */
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
void setup()
{
/* Регистрируем собственные символы с кодами 0, 1 и 2 */
lcd.createChar(0, arnie);
lcd.createChar(1, skull_and_bones);
lcd.createChar(2, lightning);
/* Начинаем работу с дисплееем */
lcd.begin(LCD_WIDTH, LCD_HEIGHT);
}
typedef void (*LCD_demo)();
/* Это список демо-функций. Добавляйте свои или меняйте их порядок,
* если хотите разнообразить этот скетч (:
*/
LCD_demo const demos[] =
{
showArnie,
showWarning,
showScrolling,
showAutoscroll,
showRTL
};
/* Этот макрос - обычный "синтаксический сахар". Мне просто влом писать
* по 10 почти одинаковых циклов for. Конечно, в серьёзном коде такое лучше не писать.
*/
#define dotimes(n, code) for (int i = 0; i < (n); ++i) code;
void loop()
{
dotimes(sizeof(demos) / sizeof(demos[0]),
{
demos[i](); // запускаем очередную демонстрацию
/* Даём насладиться её последними "кадрами", после чего очищаем экран */
delay(2000);
lcd.clear();
delay(1000);
});
}
void showArnie()
{
lcd.cursor(); // показываем курсор
lcd.blink(); // заставляем его мигать
delay(1000);
lcd.write(0); // выводим наш собственный символ с кодом 0 (ноль)
lcd.write(' ');
delay(1000);
lcd.print("I'll be back"); // угадай, кто на экране (:
delay(1000);
lcd.noBlink(); // больше мигать не нужно
lcd.noCursor(); // прячем курсор
}
void showWarning()
{
/* Так как коды наших собственных символов - от 0 до 7,
* можно смело использовать запись символов в строке при помощи
* восьмеричных кодов: \1, \2 и т.д.
* НО: код 0 (ноль) в C и C++ используется в качестве маркера конца строки,
* так что используйте lcd.write(0) для вывода нулевого символа.
*/
lcd.print("Smoke kills \1"); // в конце строки будет черепок с костями
delay(2000);
lcd.setCursor(0, 1); // переходим на следующую строку
/* Можно вывести молнию как в начале, так и в середине */
lcd.print("\2 AC/DC \2 rocks");
}
void showScrolling()
{
lcd.print("I'm scrolling");
delay(1000);
/* Прокручиваем текст вправо за экран */
dotimes(16,
{
lcd.scrollDisplayRight();
delay(150);
});
/* И возвращаем на место, прокручивая влево */
dotimes(16,
{
lcd.scrollDisplayLeft();
delay(150);
});
}
void showAutoscroll()
{
lcd.setCursor(LCD_WIDTH - 2, 0);
lcd.autoscroll(); // включаем автопрокрутку
const char *text = "autoscroll";
/* Печатаем строку буква за буквой. Текст будет "выползать" справа. */
dotimes(strlen(text),
{
lcd.write(text[i]);
delay(200);
});
lcd.noAutoscroll(); // выключаем автопрокрутку
}
void showRTL()
{
lcd.setCursor(LCD_WIDTH - 1, 0);
lcd.rightToLeft(); // теперь пишем справа налево
const char *text = "tfel-ot-thgir"; // похоже на заклинание
/* Печатаем строку буква за буквой. Текст будет выводиться задом наперёд. */
dotimes(strlen(text),
{
lcd.write(text[i]);
delay(200);
});
lcd.leftToRight(); // пишем слева направо
}
Видеозапись процесса работы этого скетча:
Надеюсь, вас не испугал такой объём кода. Зато всё в одном скетче, а не в нескольких, как в примерах к библиотеке LiquidCrystal. Исходный код с комментариями на английском языке также доступен вот и на GitHub в .
Теперь о кириллице. Дело в том, что китайцы решили, что поддержка кириллицы — это значит произвольным образом раскидать по таблице знаков кириллические символы, без соответствия какой-либо кодировке. Один добрый человек, , в далёком 2010 году написал библиотеку LiquidCrystalRus, которая умело справляется с китайской кириллицей, делая её поддержку прозрачной. Однако с тех пор она малость устарела, поэтому я, да не осудит меня автор, её освежил и выкладываю .
Напишем с её помощью русский вариант «Hello, World»:
Теперь вы знаете всё о работе с библиотекой LiquidCrystal, и в ваших силах создать более функциональное устройство с LCD-дисплеем — нужно только проявить фантазию (:
Для написания статьи были использованы:
по работе с LCD на официальном сайте Arduino
к библиотеке LiquidCrystal
Arduino-совместимая плата
LCD-дисплей
Удобные соединительные
Беспаечная макетная плата
Выражаю всяческие благодарности и за железо и помощь в подготовке статьи, а также Илье Данилову за библиотеку с поддержкой кириллицы.
Спасибо за спасибо! Обозначения на фотках специально тщательно вырисовывал, потому что для меня самого обычные схемы не очень-то наглядны — слишком серы и скучны (:
Может кто-нибудь подробнее объяснить куда скопировать папку LiquidCrystalRus? Сам скопировал сюда \arduino\libraries. Но при компиляции появляется куча ошибок:
In file included from HelloWorldRus.cpp:1:
C:\Users\Дмитрий\Desktop\arduino-1.0-rc2\libraries\LiquidCrystalRus/LiquidCrystalRus.h:16: error: expected class-name before '{' token
C:\Users\Дмитрий\Desktop\arduino-1.0-rc2\libraries\LiquidCrystalRus/LiquidCrystalRus.h: In constructor 'LiquidCrystalRus::LiquidCrystalRus(uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t)':
C:\Users\Дмитрий\Desktop\arduino-1.0-rc2\libraries\LiquidCrystalRus/LiquidCrystalRus.h:21: error: class 'LiquidCrystalRus' does not have any field named 'LiquidCrystal'
C:\Users\Дмитрий\Desktop\arduino-1.0-rc2\libraries\LiquidCrystalRus/LiquidCrystalRus.h: In constructor 'LiquidCrystalRus::LiquidCrystalRus(uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t)':
C:\Users\Дмитрий\Desktop\arduino-1.0-rc2\libraries\LiquidCrystalRus/LiquidCrystalRus.h:28: error: class 'LiquidCrystalRus' does not have any field named 'LiquidCrystal'
C:\Users\Дмитрий\Desktop\arduino-1.0-rc2\libraries\LiquidCrystalRus/LiquidCrystalRus.h: In constructor 'LiquidCrystalRus::LiquidCrystalRus(uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t)':
C:\Users\Дмитрий\Desktop\arduino-1.0-rc2\libraries\LiquidCrystalRus/LiquidCrystalRus.h:34: error: class 'LiquidCrystalRus' does not have any field named 'LiquidCrystal'
C:\Users\Дмитрий\Desktop\arduino-1.0-rc2\libraries\LiquidCrystalRus/LiquidCrystalRus.h: In constructor 'LiquidCrystalRus::LiquidCrystalRus(uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t)':
C:\Users\Дмитрий\Desktop\arduino-1.0-rc2\libraries\LiquidCrystalRus/LiquidCrystalRus.h:40: error: class 'LiquidCrystalRus' does not have any field named 'LiquidCrystal'
HelloWorldRus.cpp: In function 'void setup()':
HelloWorldRus.pde:-1: error: 'class LiquidCrystalRus' has no member named 'print'
В Arduino 1.0 чуточку поломали обратную совместимость.
Создал в репозиториях на GitHub отдельные ветки arduino-1.x для библиотек , и , не забудьте обновить все три. Можете через git:
Как и в прошлый раз — в arduino-1.0-rc2\libraries. Можно также создать папку «libraries» в папке, где у вас скетчи лежат (у вас это C:\Users\Дмитрий\Documents\Arduino), и распаковать в неё — так даже правильнее будет (:
а на самом деле в последней строчке должно быть :else return LiquidCrystal::write(out_char); иначе при вводе русских букв они в начале обрабатываются и выводятся как русские, а потом выводятся как «кракозябры» пр обработке символов из основной кодировки. Исправьте пожалуйста исходник.
На самом деле, эта ошибка уже давно была исправлена, а исправленный код лежал в репозитории. Но, раз уж вы напомнили, я обновил библиотеку для совместимости с Arduino 1.x и залил в репозиторий, а заодно обновил — теперь он будет браться напрямую с GitHub.
Версия LiquidCrystalRus для Arduino 1.0 есть в репозитории на GitHub в ветке arduino-1.x, брать .
Т.к. LiquidCrystalRus требует также библиотеки LineDriver и LiquidCrystalExt, нужно скачать и их: и .
Позже я обновлю ссылки на наши библиотеки во всех статьях.
Вот незадача. Постараюсь завтра посмотреть; если не получится — в понедельник. Во втором случае черканите в личку в понедельник — на всякий случай: я тут неравный бой с ARM веду, могу и забыть ненароком.
Не скажите почему таблица символов в даташите на НД44780 отличается от стандартной таблице, которая прописана и в CV AVR и везде в статьях выдается? Спасибо.
Да точно, единственное отличие. Но как это — между 5 вольтами и 15 ногой??? Можно сказать между Шестью и восемью вольтами или между Тринадцатой и пятнадцатой ногой, это же совсем разные системы счисления!..
И вопрос не по теме — Когда планируется следующий урок по ARM???
Только заметил новый коммент. Раз по теме всё понятно, отвечаю не по теме — урок почти дописан, скоро будет. В праздники я честно балду гонял, поэтому так долго (:
Если попадётся когда-нибудь недорогой вариант и будет время — почему бы и нет. Дисплей, использованный в статье по ссылке, стоит около 20$, а показывает всего-то 20 символов. Дорогое удовольствие получается.
Извините если не в тему, но тоже про дисплей. Попалась мне мини-АТС LG LKD-30DS с дисплеем 24х2 18 ножек имеет. Есть ли какие-нибудь аналоги этого дисплея, чтобы можно было сориентироваться с выходами? Хотел бы подключить к крафтдуино. На нем написано P24201B-C R4-H(R.1). Имеет на борту 3 микросхемы (капли). Если кто может помочь, буду очень рад :)
Скажите а можно подключить 2 таких дисплея к одной Arduino? Точнее я понимаю что можно. Интересует можно ли использовать какие-то выводы ардуины как общие для двух дисплеев? Для экономии. Ну, к примеру, могу я подключать к разным выводам ардуины только входы DB4-DB7 дисплеев?
Я имел ввиду можно ли какие-то из этих выводов использовать как общие для нескольких дисплеев. Понятно что можно прописывать
LiquidCrystalRus lcd_1(12, 11, 5, 4, 3, 2);
LiquidCrystalRus lcd_2(13, 10, 9, 8, 7, 6);
Но это ведет к лишним подключениям проводов, да и выводы занимает. На Arduino Mega их 54 конечно, но мне есть чем их занять.
Судя по всему, так можно сделать, только нужно, чтобы как минимум линии ENABLE были свои для каждого дисплея. Я так не пробовал ещё, сужу по коду библиотеки.
Своими раскопками получил такую же информацию. Да вот проблема что попробовать не могу. Дисплеи в пути еще, а распланировать нужно. Если есть возможность попробовать повесить 2 дисплея с разделением только пина E был бы премного благодарен за информацию о результатах испытаний.
Интуиция нас не обманула: всё работает именно так — раздельные линии ENABLE, все остальные общие. Подключал два дисплея — 16x2 и 8x2, оба в 4-битном режиме. Завёл счётчик и выводил его значение попеременно то на один дисплей, то на другой. Всё работает без проблем.
Комментарии (47)
RSS свернуть / развернутьnoonv
До меня картинки доходят намного лучше чем буквы )))
skystorm
P.S skystorm, согласен)
DrTriton
burjui
George
Вот тут статья об этом на английском
nubas
Тут один товарищ ещё хотел сервами через сдвиговый регистр порулить — об этом тоже будет (:
burjui
У кого собрана такая схема можете плиз проверить…
sined
burjui
In file included from HelloWorldRus.cpp:1:
C:\Users\Дмитрий\Desktop\arduino-1.0-rc2\libraries\LiquidCrystalRus/LiquidCrystalRus.h:16: error: expected class-name before '{' token
C:\Users\Дмитрий\Desktop\arduino-1.0-rc2\libraries\LiquidCrystalRus/LiquidCrystalRus.h: In constructor 'LiquidCrystalRus::LiquidCrystalRus(uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t)':
C:\Users\Дмитрий\Desktop\arduino-1.0-rc2\libraries\LiquidCrystalRus/LiquidCrystalRus.h:21: error: class 'LiquidCrystalRus' does not have any field named 'LiquidCrystal'
C:\Users\Дмитрий\Desktop\arduino-1.0-rc2\libraries\LiquidCrystalRus/LiquidCrystalRus.h: In constructor 'LiquidCrystalRus::LiquidCrystalRus(uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t)':
C:\Users\Дмитрий\Desktop\arduino-1.0-rc2\libraries\LiquidCrystalRus/LiquidCrystalRus.h:28: error: class 'LiquidCrystalRus' does not have any field named 'LiquidCrystal'
C:\Users\Дмитрий\Desktop\arduino-1.0-rc2\libraries\LiquidCrystalRus/LiquidCrystalRus.h: In constructor 'LiquidCrystalRus::LiquidCrystalRus(uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t)':
C:\Users\Дмитрий\Desktop\arduino-1.0-rc2\libraries\LiquidCrystalRus/LiquidCrystalRus.h:34: error: class 'LiquidCrystalRus' does not have any field named 'LiquidCrystal'
C:\Users\Дмитрий\Desktop\arduino-1.0-rc2\libraries\LiquidCrystalRus/LiquidCrystalRus.h: In constructor 'LiquidCrystalRus::LiquidCrystalRus(uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t)':
C:\Users\Дмитрий\Desktop\arduino-1.0-rc2\libraries\LiquidCrystalRus/LiquidCrystalRus.h:40: error: class 'LiquidCrystalRus' does not have any field named 'LiquidCrystal'
HelloWorldRus.cpp: In function 'void setup()':
HelloWorldRus.pde:-1: error: 'class LiquidCrystalRus' has no member named 'print'
ivanserov
Создал в репозиториях на GitHub отдельные ветки arduino-1.x для библиотек , и , не забудьте обновить все три. Можете через git: или скачав их архивами:
burjui
ivanserov
burjui
ivanserov
burjui
ivanserov
ivanserov
size_t LiquidCrystalRus::write(uint8_t value)
{
uint8_t out_char = value;
if (value >= 0x80) // UTF-8 handling
{
if (value >= 0xc0)
utf_hi_char = value — 0xd0;
else
{
value &= 0x3f;
if (!utf_hi_char && value == 1)
out_char = 0xa2; // РЃ
else if (utf_hi_char == 1 && value == 0x11)
out_char = 0xb5; // С‘
else
out_char = pgm_read_byte_near(utf_recode + value + (utf_hi_char << 6) — 0x10);
return LiquidCrystal::write(out_char);
}
}
return LiquidCrystal::write(out_char);
}
а на самом деле в последней строчке должно быть :else return LiquidCrystal::write(out_char);
иначе при вводе русских букв они в начале обрабатываются и выводятся как русские, а потом выводятся как «кракозябры» пр обработке символов из основной кодировки. Исправьте пожалуйста исходник.
ventin2012
burjui
Буду признателен за рабочую версию библиотеки.
BlkDem
Т.к. LiquidCrystalRus требует также библиотеки LineDriver и LiquidCrystalExt, нужно скачать и их: и .
Позже я обновлю ссылки на наши библиотеки во всех статьях.
burjui
Все получилось.
BlkDem
BlkDem
burjui
BlkDem
скомпилировался только тогда, когда убрал строчку #include <LiquidCrystal.h>. Ну и кракозяблы соответственно
Diemon
deneb
SinauRus
Это единственное отличие в подключении этого дисплея, всё остальное — так же, как в статье.
burjui
И вопрос не по теме — Когда планируется следующий урок по ARM???
SinauRus
SinauRus
burjui
daitel
lU5esdYP
burjui
ivanserov
ivanserov
ivanserov
Trump
ivanserov
ivanserov
LiquidCrystalRus lcd_1(12, 11, 5, 4, 3, 2);
LiquidCrystalRus lcd_2(13, 10, 9, 8, 7, 6);
Но это ведет к лишним подключениям проводов, да и выводы занимает. На Arduino Mega их 54 конечно, но мне есть чем их занять.
Trump
burjui
Trump
Жёлтые провода — это ENABLE.
burjui
Trump
спасибо большое
source
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.