Что нужно для программирования микроконтроллеров

AVR и USB. Подключаем устройства на AVR к USB порту

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

Такие интерфейсы как COM, MIDI, LPT широко использовались в свое время, но сейчас они морально устарели и все реже и реже встречаются в современных компьютерах в основном в компьютерах для промышленного и узкоспециализированного оборудования. Для связи собранного устройства с компьютером можно использовать всевозможные переходники конвертеры и эмуляторы, но как показывает практика они порождают множество проблем.

Для того чтобы использовать подружить USB и AVR можно пойти 3-мя путями:

Использовать аппаратную поддрежку USB интерфейса, к примеру микроконтроллера AT90USB*. Для того чтобы его использовать нужно написать для него особую прошивку. И если вашу собраное устройство не стандартного класса USB то придется для компьютера писать драйвер, который объяснит ПК с каким устройством имеем дело.

Использовать конверторы USB в какой нибудь другой интерфейст (к примеру USB-UART на микросхеме FTDI FT232RL). В качествое других интерфейсов может выступать RS232, I2C или другие. При таком подходе нам не нужно замарачиваться и знать как работает интерфейс USB, также нужда в драйвере для компьютера тоже отпадает, так как драйвера для таких конверторов уже написаны производителем.

Можно сделать все хитрее взять микроконтроллер AVR и написать для него программу которая будет эмулировать работу USB. При таком подходе возникает трудность в реализации большой скорости передачи данных. Интерфейс USB работает на большой скорости которая может быть: LowSpeed — 1,5 Mbit/s, FullSpeed — 12 Mbit/s, HighSpeed — 480 Mbit/s, а у интерфейса USB 3.0 скорость может быть еще выше. Поэтому на микроконтроллерах AVR можно сделать устройство только со скоростью LowSpeed. Для большинства самодельных устройств такой скорости вполне достаточно.

  • USBtiny;
  • V-USB;
  • Igor Cesko.

Igor Cesko первый кто сделал такой проект, он был написан на языке assembler.

После появился проект V-USB который написан на языке C с использованием ассемблерного кода Используя V-USB был сделан проект ИК приемника для компьютера.

USBtiny в свою очередь является произволным от ранней версии проекта V-USB. По возможности он уступает V-USB но зато гараздо проще теоретически и относительно легок в освоении.

Мы будем использовать проект V-USB

Проект V-USB для микроконтроллеров AVR

  • хорошая документация под код C, в результата легче разбираться;
  • у V-USB есть свободная пара идентификаторов это Vendor-ID и Product-ID;
  • работает на многих AVR микроконтроллерах, необходима частота не менее 12 МГц, 2 кБ флеш памяти и 128 байт RAM;
  • хорошая эмуляция USB 1.1 со скоростью LowSpeed устройств, только нет обработки ошибок связи и электрических характеристик.
  • проект V-USB опубликован на GNU GPLV (General Public License Version 2) также есть платная версия.

В своих USB экспериментах, прошивку для микроконтроллера писал на языке C в среде AVR-Studio 4 + WinAVR, программа для ПК была разработана при помощи среды Borland C++ Builder как самый простенький и хустрый вариант. Поэтому все следующие примеры будут такими же. От правильного выбора инструментов зависит количество головной боли на последующих шагах. По поводу того что лучше C или Assembler можно говорить много. Как по мне то нужно владеть всеми инструментами, каким-то в большей степени каким-то в меньшей и использовать тот или другой в зависимости от конкретной поставленной задачи.

Считаю важным сказать пару слов про идентификаторы VID и PID которые представляют 16-битные числа. Эти числа использует операционная система и определяет какой подгрузить драйвер. Стоимость Vendor-ID на usb.org составляет 2000$. По поводу легальности использования VID/PID можно прочитать на станчике эмбеддера BSVi. V-SUB предоставлят свободную пару VID/PID. У вас наверное возникнет вопрос «Как подключить сразу несколько устройст с однинаковыми значениями VID/PID». Подключить несколько устройств с одниковами значениями вы можете, ничего страшного в этом нет так как каждое устройство USB имеет также свой VENDOR_NAME и DEVICE_NAME идентификаторы.

Давайте попробуем собрать свое первое USB HID устройство на микроконтроллере Atmega8 и научим его общаться с компьютером при помощи интерфейса USB. Может возникнуть вопрос «почему именно HID устройство». Ответ самый простой- потому что мы не хотим замарачиваться,выносить себе мозг и писать всякие там драйвера под Windows. А когда мы подключаетм HID устройство то операционная система сама выбирает и включает необходимый драйвер. Наша программа под компьютер не будет нуждаться в установки и настройки чего либо она сразу будет использовать готовый алгоритм для работы с HID устройством.

  • Borland C++ Builder 6 -среда для разработки приложение под Windows на языке программирования C++;
  • V-USB — программа под микроконтроллеры AVR реализующая работу low-speed USB 1.1,скачатьvusb.tar.gz;
  • WinAVR — набор для разработчиков AVR, сдесь нам нужен будет GNU GCC компилятор, который автоматически интегрируется в студию;
  • AVR Studio — отличная среда для разрабоки программ под микроконтроллеры AVR.

Структура и порядок написания программы

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

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

Языки программирования микроконтроллеров: Си и Ассемблер

Мы будем писать программы на Си, который относится к языку высокого уровня. Программы на Си пишутся гораздо быстрее по сравнению с аналогичными на Ассемблере. К тому же все сложные программы пишутся преимущественно на Си.

Здесь мы не будем сравнивать преимущества и недостатки написания программ на Ассемблере и Си. Со временем, приобретя некоторый опыт в программировании МК, вы сами для себя сделаете полезные выводы.

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

3. Программа

Разберем программу на C по строкам .

В программе вставлен бесконечный цикл while(1), чтобы микроконтроллер не выполнил ничего лишнего. Все действия с портами в программе выполнены с использованием поразрядных операций в языке C. Что дало возможность управлять только одним разрядом (одним выводом микроконтроллера) порта B.

На использованном нами выводе микроконтроллера ATmega328 в Arduino UNO и Arduino Nano v3 подключен светодиод, поэтому в первой программе не придется даже собирать схему, достаточно подключить Arduino к компьютеру.

Не совсем USB-устройство

Проект, для которого я делаю канал связи с ПК, называется «Teslafon». Это название музыкальных катушек тесла с микроконтроллерным управлением (описание их работы тут). Пока катушка является автономным устройством и ни к чему не подключается, но недавно мне пришла идея сделать управление молниями с ноутбука. Несмотря на то, что тема специфическая, в сети можно найти примеры даже на неё, но там всё довольно индивидуально и я решил пойти своим путём.

Так как слона лучше есть по частям, я раздробил задачу на несколько подзадач, первая из которых — тема данной статьи. Но не подумайте, что я хочу подключить катушку тесла напрямую к ноутбуку (мой ноутбук мне дорог). Катушка тесла это генератор адских помех и наводок, а значит между ней и ноутбуком должно быть не только существенное расстояние, но и промежуточное устройство-изолятор на несколько мегавольт. Его-то я и хочу подружить с ПК. Вдаваться в подробности катушек тесла не буду, это уже другая история. Просто скажу, что мы сделаем универсальную заготовку USB-устройства, которую вы сможете использовать в своём проекте, а я в своём.

↑ 3. Как прошивать контроллер, и какие дополнительные приборы и акссесуары нужны для удобной работы с ними?

Используем датагорский кит — программатор Project-005 «D-AVR910». Кроме этого, нужно будет приобрести макетные платы, блок питания с выходным напряжением 5 Вольт. Можно в качестве БП с малыми пульсациями использовать наш кит Project-006 «POWER FILTER», применив стабилитрон на 5 Вольт.
Возможно, со временем мы с Игорем предложим проект для сборки отладочной платы.

Программирование микроконтроллеров в AtmelStudio 6. Часть 1. Первые шаги

Управление Ардуино через компьютер

Функция Serial.available() получает количество байт доступных для чтения из последовательного порта. Это те байты которые отправлены с компьютера и записаны в буфер последовательного порта. Буфер Serial monitor Arduino может хранить максимум до 64 байт. Функция используется также при взаимодействии Bluetooth модуля к Ардуино и полезна при отладке устройства на этапе проектирования.

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

С чего все началось?

Все началось с кампании на Kickstarter. Дэмьен Джордж (Damien George), разработчик из Англии, спроектировал микроконтроллерную плату, предназначенную специально для Python. И кампания «выстрелила». Изначально была заявлена сумма в 15 тысяч фунтов стерлингов, но в результате было собрано в шесть с половиной раз больше — 97 803 фунта стерлингов.

Автор проекта приводил целый ряд преимуществ своей платформы в сравнении с Raspberry Pi и Arduino:

Мощность — MP мощнее в сравнении с микроконтроллером Arduino, здесь используются 32-разрядные ARM-процессоры типа STM32F405 (168 МГц Cortex-M4, 1 Мбайт флеш-памяти, 192 Кбайт ОЗУ).

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

Отсутствие компилятора — чтобы запустить программу на платформе MicroPython, нет необходимости устанавливать на компьютер дополнительное ПО. Плата определяется ПК как обычный USB-накопитель — стоит закинуть на него текстовый файл с кодом и перезагрузить, программа тут же начнет исполняться. Для удобства все-таки можно установить на ПК эмулятор терминала, который дает возможность вписывать элементы кода с компьютера непосредственно на платформу. Если использовать его, тебе даже не придется перезагружать плату для проверки программы, каждая строка будет тут же исполняться микроконтроллером.

Низкая стоимость — в сравнении с Raspberry Pi платформа PyBoard несколько дешевле и, как следствие, доступнее.

Файлы

Related items

  • Библиотека для опроса кнопок
  • Работа с SD картой. Воспроизведение wav файла. Ч3
  • Работа с SD картой. Подключение к микроконтроллеру. Ч1
  • AVR315: Использование TWI модуля в качестве ведущего I2C устройства
  • ATtiny10. Самый маленький микроконтроллер AVR

Comments

Есть ли какие-либо определенные подходы
если поток данных между МК и ПК насыщен
( например идут данные разной структуры ,
при этом идет посылка определенных команд
) .
Или тут все зависит от мастерства программировани я .
На ПК я использую VB6 . Там почти все
делаю через обработчик событий CommEvent .
Может быть на ПК в этом случае есть более
фунциональный язык .
Со стороны МК использую CodeVision .

Использовать приемный и передающие fifo буферы. А для «распознавания» принятых данных — state machine(автомат ) на таблицах или switch`е. Больше тут ничего не придумаешь.

Доброго времени суток!alexander shahbazov можете объяснить(на форуме) по подробнее про использование обработчика событий CommEvent(компонент MSComm1). Я сам программирую в VB6, с недельку назад разобрался с USART-ом на Mege8535. Буду очень благодарен! 🙂

Dim chr As String

Private Sub ATmega8_OnComm()
Select Case ATmega8.CommEvent
Case comEvReceive
chr = ATmega8.Input
‘Здесь уже кому что надо
End Select
End Sub

Собрал на mege48. При приеме символов не отображает практически ничего — черный квадратик. если отправлять с терминала строку с абзацем — показывает абзац.
При отправке на компе принимается группа из 6-7 символов. притом 5 из них одинаковые, а остальные какие-то кракозяблы. Ну никак это не похоже на ОК.
Вчем мой косяк?

— Проект в статье написан для mega8535. Для другого микроконтроллер а его нужно перекомпилировать.
— Кракозябы часто возникают, когда скорость обмена мк и компа не совпадают. У меня в схеме тактовая частота мк — 8МГц, скорость обмена — 9600.

Угу. Перекомпилирова л естественно под 48й кристалл. Фьюзы стоят на внутренний 8 мгц по-умолчанию. скорость 9600. а кракозяблы остались.

Какой компилятор?
У mega48 названия битов и регистров модуля USART отличаются от mega8535 и при перекомпиляции из нужно исправлять. Скинь мне проект на microsmaster’со бака’rambler.ru , я гляну его

Собрал на меге168 работает хорошо.
Только мах232 почемуто на 3,3В не работает.Знаю что 5В надо, но другом проекте другой мах232 работал отлично.

Помогите настроить проект под Atmega8515? я новичек и что-то не разберусь IAR выдает
Error[Pe020]: identifier «UCSZ1» is undefined
Error[Pe020]: identifier «UCSZ0» is undefined
Error[Pe020]: identifier «UDRE» is undefined

Помогите настроить проект под Atmega8515? я новичек и что-то не разберусь IAR выдает
Error[Pe020]: identifier «UCSZ1» is undefined
Error[Pe020]: identifier «UCSZ0» is undefined
Error[Pe020]: identifier «UDRE» is undefined

Разрешаем использование имен битов определенных в хидер файле
В General Options > System ставим галочку Enable bit definitions in I/O-Include files.

интерестно, в нете в некоторых схемах одни соединяют ноги разьема rs232 некоторые нет, в чем разница и что лучше?

Полная версия стандарта RS-232 включает 9 сигналов. В большинстве случаев пользуются сокращенным вариантом — 3 провода (RXD, TXD, GND). Просто так удобнее.

Изучаю работу UART по Вашему примеру 🙂 Но возникла проблема при приеме символов. На передачу все работает замечательно, а прием отсутствует 🙁 В прерывание заходит «через раз» и регистр UDR имеет нулевое значение. Выставляется ошибка кадрирования. Все собрано «в железе» контроллер AtMega162 (программа естественно исправлены на него). Это вероятней всего аппаратная проблема?

Может быть проблема в несогласованнос ти скоростей обмена данными терминала и мк. Ну то есть в терминале выставлена одна скорость, а микроконтроллер посылает/приним ает данные с другой. От чего тактируется мк и какая у него частота?

Привет всем, не уверен, что правильно понял схему:
1. prog connector — это программатор?
2. txd и rxd — это uart/usart переходник?
Спасибо за ответы)

Привіт!
Заюзав ваш приклад використання USART
та знайшов помилку. незнаю як в старих версіях WinAvr але в нових версіях оголошувати переривання потрібно
ISR(USART_TXC_v ect)а не ISR(USART_TX_vect)
ISR(USART_RXC_vect)а не ISR(USART_TX_ve ct). до цього в мене просто ‘завісав’ МК Atmega8.

Написал программу. МК(mega8) передает символы на ПК через usb-uart переходник(bm80 51) только если подключен программатор (avr910).Без него не пересылает. Кто-нибудь сталкивался с подобным?

Подал на него «+5»- все равно, — без программатора, подключенного к ПК символы по Usart’у не передаются.

Pashgan, понял я в чем дело. Чуть голову не сломал от раздумий 🙂 . UART я подключал как показано на схеме: RXD и TXD, без земли (она не указана).Подсое динил землю — все заработало 🙂 .

По-моему, загружать главный цикл примитивной отправкой сообщения — не совсем рационально, там и так достаточно работы будет. Гораздо интереснее заставить это делать сам USART. Для этого не вызываем SendChar(. ) столько раз, сколько символов в буфере отправки, а пользуем прерывание по опустошению UDR. Когда нам требуется отправить сообщение — грузим UDR байтом из буфера по нулевому индексу и сразу разрешаем прерывание UDR. Цепочка такая: первый байт проваливается-U DR опустошается-во зникает прерывание-в прерывании считывается второй байт-прерывание сбрасывается-по опустошению UDR возникает прерывание-. и т.д. Только в прерывании проверять на равенство взятого из буфера байта 0 — признак конца строки. Если взяли 0 — ничего не отправляем и глушим прерывание сбросом бита UDRE.
Таким образом, USART самостоятельно выгребет весь буфер и сам себя успокоит.
Идея любезно подсказана DI HALT’ом. (dihalt.ru)

А что означает если по USART всегда передается 00000000, и ничего не принимается не при каких условиях?

так постоянно нули передавать ещё проще — грузи их по прерыванию UDR и всё
а на практике такая потребность часто возникает?

подключил Вашу программу, символ отсылаю, в ответ приходит — это первое.
Второе, пишу if (sym == ‘q’) if (sym == ‘w’) Вообще не работает, тыкаю на любую кнопку загарается LED и не гаснет

Подключать на прямую без МАХ232 но лучше FT232BM заменить на FT232RL. У RL обвязки никакой не надо там всего 2 конденсатора по питанию достаточно (а цена одинаковая).

К стати не соединяйте Экран USB разъемов с землей, FT232 к этому очень чувствительна и может начать сбоить(типа устройство не опознано) На ноутбуке этого не будет на на стационарном компе может получится.
Я очень долго с этим мучился.
К стати спасибо за доходчивое объяснения)))

Всем привет. Я еще пока очень зелен в МК. Как в AVR Studio 5 быть с этой программой? К примеру прерывание если правильно понимаю __enable_interr upt(); он не понимает. Читал на форумах что в разных компиляторах все команды на одном и том же языке вводятся по разному. Как узнать все эти разности? Может есть где описание типа к примеру для AVR Studio 5 эта команда так будет выглядеть, а для WINAVR вот так. Может кто встречал в интернете подобное. За ранее всем благодарен.

Если кто знает, как в AVR studio 5 при наборе кода сделать что бы выпадал список с подсказками как например вот в этом видео на пятой минуте просмотра http://www.youtube.com/watch?v=3Koa6oy53Os&feature=related . Всем еще раз спасибо

Здравствуйте!
Пишу диплом, и практически сразу стллкнулся с проблемой. Пишу в iar а отлаживаю в протеусе и авр-студии. Необходимо отправлять 3-и 2-ух байтных числа, как только отправляю байт (например все единицы), приходят одни нули. При проверке в студии обнаружил, что когда помещаю число в UDR, на следующем цикле UDR обнуляется. Прочитал что на самом деле для передачи используется другой регистр, а UDR на подобии буфера. Тогда попробовал присваивать UDR одно число и в следующей строчке другое, но UDR всё равно обнуляется, а не ждёт пока регистр отправки отправит предыдущий.
Думаю вопрос глупый, и что я банально что-то упустил из виду=)

присоединяюсь к вопросу- как проверить полученный символ? вот так-
if (data==’A’)
stat=1;
>
if (data==’B’)
stat=0;
>
while (stat)

Так же как и в примере
Code:
sym = USART_GetChar(); //читаем буфер
if (sym) < //если что-то приняли, то
LCD_Goto(6,0);
LCD_WriteData(sym); //отображаем на lcd принятый символ
USART_SendChar(‘O’); //отвечаем компу «Ok »
USART_SendChar(‘k’);
USART_SendChar(‘ ‘);
>

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

Code:
sym = USART_GetChar(); //читаем буфер
if (sym)< //если что-то приняли, то

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

Делаю вроде по аналогии, но без дисплея. На переходнике USB-UART светодиод моргает — символ отправлен. но Ок нет =( Земля и от LPT программатора и от переходника подключены, питание есть, но молчок

кристалл mega8515, скорость 9600, частота 8000000

поменял на:
1843200 hz, 115200 бод, плучилось 0

светодиоды на переходнике горят оба — символ отправлен и что-то принято, но в одном терминале (keterm) отобраюжаются буквы, в другом SimpleTerm — вопросы, в третьем Advanced Serial Port Monitor — те же буквы. В терминалах выбирал 115200 бод.

Я взял проект, поменял тип микроконтроллер а на mega8515 и запустил компиляцию. В Протеусе полученная прошивка сразу же заработала (тактовая 8 МГц, скорость обмена 9600). В железе нет возможности проверить.

Через что подать символ по UART в Протеусе? В протеусе добавил компонент com, подключил к 8515. и непонятные символы пошли в ответ

Здравствуйте!По дскажите,пожалу йста как организовать мультипроцессор ный обмен между мастером и двумя слейвами.Принци п понимаю,смотрел пример из datasheet на mega8.В Proteus удалось добится только одноразового аппаратного сброса MPCM при прохождении «1» в 9-ом разряде.Дальше- затык.В железе не пробовал пока.

Просто всё — разрешаете прерывание по приёму байта, в прерывании пишите данные в кольцевой буфер, а в основной программе обрабатываете принятые данные.

Гдето я наверно накосячил, так же и пытался сделать
если у кого есть такой кусочек кода для приема, буду благодарен)

Гдето я наверно накосячил, так же и пытался сделать
если у кого есть такой кусочек кода для приема, буду благодарен)

Например так:
Code:
#define RX_BUFFER_SIZE 100
volatile uint8_t RxBuffer[RX_BUFFER_SIZE];
volatile uint8_t RxNext, RxFirst;
ISR(USARTC0_RXC_vect)
uint8_t rx_next=RxNext;
RxBuffer[rx_next]=USARTC0.DATA;
if (++rx_next>=RX_BUFFER_SIZE)
rx_next=0;
RxNext=rx_next;
>

void UsartReceive()
uint8_t rx_first=RxFirst, rx_next=RxNext;
while (rx_first!=rx_next) uint8_t new_byte=RxBuffer[rx_first];
// обработка данных
//
if (++rx_first>=RX_BUFFER_SIZE)
rx_first=0;
>
RxFirst=rx_first;
>

Спасибо, буду ковырять косяк, вроде похоже делал, но принимает только первый байт, второй почему-то ноль
С примером проще разбираться))

здравствуйте, разглядывал много схем с уарт преобразователя ми, и что увидел, на некоторых есть резисторы на линиях rx и tx, на некоторых нету, а на некоторых есть резистор только на одной линии, так вот собственно нужны ли всё таки там резисторы? и зачем?
предпологаю для защиты, например по уарту «плюётся» еденичка, а на втором конце по случайности «мёртвая» земля

и какая сторона в состоянии покоя подтягивает линию к 5-ти вольтам?
мне кажется tx подтягивает к 5-ти вольтам, а rx всегда может только слушать линию(то есть всегда в высокоимпедансн ом состоянии)?

Здравствуйте Pashgan, собрал Вашу схему на mega8515 немного поменял код — все отлично работает. Пошел дальше сделал программу на ПК которая отсылает побайтно содержимое бинарника и сразу столкнулся с проблемой: программа не принимает 0х00 и виснет, так как от контроллера нет ответа. Я попытался в файле usart.c в прерывании подписать еще одну переменную, которая принимает значение 1 при событии приема байта. Вообще корректно ли так делать или нет? С++ начал учить совсем недавно. Далее, попытался переделать функцию USART_GetChar на возвращение структуры состоящей из двух символов буфера и флага приема байта. Пытался компилировать в CVAVR но ни чего не получилось — вообще не пойму в чем проблема вот код
Code:
#include «usart.h»
//однобайтный буфер
volatile unsigned char usartRxBuf = 0;
unsigned char fl = 0;
struct my_strct ;
#define RXCIE 7
#define RXEN 4
#define TXEN 3
#define URSEL 7
#define UCSZ1 2
#define UCSZ0 1

//чтение буфера
my_strct USART_GetChar(void)// на это место компилятор ругается ‘(‘ expected
<
my_strct my;
//unsigned char tmp;
unsigned char saveState = SREG;
#asm(«cli»);
my.buf=usartRxBuf;
my.flg=fl;
//tmp = usartRxBuf;
usartRxBuf = 0;
fl=0;
SREG = saveState;
return my;
//return tmp;
>

//прием символа по usart`у в буфер
interrupt [USART_RXC] void usart_rxc_my(void)
usartRxBuf = UDR;
fl=1;
>

Оцените статью
Fobosworld.ru
Добавить комментарий

Adblock
detector