Подключение lcd-дисплея st7565 к микроконтроллеру msp430

Уроки MSP430 LaunchPad. Урок 14: Текстовый дисплей

Мы в одном шаге от создания полноценного измерительного прибора. Все, что нам осталось, это сделать результаты измерения доступными за пределами отладчика. Для этого есть несколько способов. Один из них, выводить результат измерения на ЖК-дисплей, как это делается в бытовой технике. В этом уроке, мы научимся использовать стандартный ЖК-модуль с LaunchPad.

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

Для этого урока вам необходим ЖК-дисплей, которого у вас может и не быть. Если нету, рекомендую купить один.

Эти дисплеи очень распространены и стоят не дорого. Они бывают разных размеров и типов, здесь мы будем использовать стандартный текстовый 16х2 ЖК-модуль с интерфейсом HD44780. Их можно купить где угодно, например на eBay, можете выбрать любой, какой вам нравится, но убедитесь что, он работает от напряжения 3.3 В и не переделан для работы по последовательному интерфейсу (I2C/TWI).

Если вам хочется большой модуль (например 20х4), как пожелаете, работают они одинаково. Цвет можете выбрать любой.

Я применил ЖК-модуль с управляющим чипом ST7066, который использует вездесущий интерфейс HD44780. (Если вам эти названия ни о чем не говорят, не беспокойтесь, просто примите к сведению, что у нас есть стандартный интерфейс для связи между MSP430 и дисплейным модулем).

Этот интерфейс работает через 8-битную параллельную шину для обмена данными между микроконтроллером и дисплеем. Если представить себе 8 каналов данных, да плюс еще 3 дополнительных контрольных канала, можно быстро превысить количество доступных выводов портов вашего MSP430. По факту, даже если вы используете G2211 без внешнего кварца, что освобождает два вывода P2.5 и P2.

6, мы получаем только 10 выводов на портах, трёх нам не хватает, 11 нужно для дисплея и 2 выхода компаратора для измерителя ёмкости.

К счастью, интерфейс HD44780 (и тот, что у ST7066), позволяет посылать данные двумя 4-битными порциями, и до тех пор, пока у нас не возникнет необходимость читать данные из дисплея, мы можем использовать только 6 выводов для него, что позволит нам ужать компаратор и дисплей в восемь выводов порта P1 на нашем G2211.

Мы подошли к лимиту этого микроконтроллера, это хорошая мотивация перейти на более продвинутые MSP430 в будущем! (Справедливости ради заметим, что LaunchPad версии 1.5 комплектуется G2553, самой продвинутой моделью Value Line, и выходов в нем побольше, а если нужно принципиальное увеличение количества выходов, придется отказаться от корпусов PDIP, по крайней мере в MSP430, например у AVR есть большие PDIP. – Прим. пер.)

Стандартный ЖК-модуль имеет 16 выводов (14 без подсветки). Первые несколько предназначены для питания (могут быть в двух местах, при наличии подсветки) и настройки контраста. Вывод 1 (обозначен как Vss) должен быть соединен с землей на вашем LaunchPad. Вывод 2 (Vdd) соединен с питанием Vcc на вашем LaunchPad. Если вы используете вывод подсветки 15 (LED+), он так же подсоединяется к Vcc и вывод 16 (LED-) к земле. (Всё это проще всего располагать на макетной плате (breadboard)). Вывод 3 (V0), контролирует контрастность экрана. Если у вас есть переменный резистор на 10 кОм, присоедините этот вывод к среднему контакту резистора, а два крайних контакта соедините с землей и питанием, и вы сможете настраивать контраст. Если резистора нету, просто заземлите этот вывод, будет смотреться не так хорошо как могло бы, но работать будет.

Остается 11 выводов на контроль и данные. Три контрольных линии, это выводы 4 (RS), 5 (R/W) и 6 (E). Вывод чтения/записи (R/W) нам не понадобится, и соединив его с землей, мы включим постоянный режим чтения у дисплея. Мы не сможем что-либо считать с дисплея (вроде положения курсора, состояния флага занятости и т.д.), но это даст нам один свободный вывод на MSP430.

Для контроля дисплея мы будем использовать выводы Выбор Регистра – Register Select (RS) и Готовность – Enable (E). Последние выводы 7-14 (D0-D7), это шина данных. Можно считать эти выводы такими же, как и восемь выводов порта P1 на MSP430, – D0 это первый бит, D1 второй, и т.д.

Если мы используем полный порт ввода/вывода на MSP430 для шины данных, просто соединим соответствующий вывод порта с таким же по номеру выводом шины данных, и избавим себя от сложностей создания виртуального порта с нестандартным расположением выводов внутри программы. Но, т.к. на G2211 не хватает портов для этого, мы просто используем 4-битный режим ввода.

Для него используются выводы D4-D7 дисплейного модуля. Выводы D0-D3 останутся не присоединенными.

В программе измерителя ёмкости нужно произвести замену рабочих выводов, из-за использования ЖК-модуля. Теперь мы будем использовать P1.1 как TA0.0 вместо CA1, и используем P1.2/CA2 как неинвертирующий вход компаратора. Вывод P1.0 будет контролировать RS, P1.3 контролировать E, выводы P1.4-P1.7 будут контролировать D4-D7 соответственно.

Обратите внимание на то, что вывод P1.3 в LaunchPad, соединен с кнопкой, это не должно мешать работе программы, но т.к. он подтянут резистором к питанию, это будет приводить к повышенной утечке тока, когда мы будем сбрасывать E.

К несчастью, на LaunchPad не предусмотрена перемычка на кнопке S2, как на выводах P1.0 и P1.6 светодиодов, так что оставим это как есть. И пока мы об этом говорим, убедитесь, что сняли перемычки с двух светодиодов и TXD/RXD.

(Здесь вам должно стать понятно, почему в новом LaunchPad отсутствует подтягивающий резистор на P1.3 – прим. пер.)

После того, как мы всё соединили, посылка команд и символов на дисплей простая задача. На самом деле, это можно делать даже руками, без микроконтроллера! Основной принцип здесь, это запись инструкций на выводы шины данных и подача импульса на E. Инструкция считывается по спадающему фронту на E, вот почему необходим импульс. Если RS сброшен, то инструкция воспринимается как команда контроллеру ЖК-модуля, если RS установлен, то как код символа для вывода.

Для примера, посмотрим команды, необходимые нам для установки дисплейного модуля в 4-битный режим. Инструкция «Выбор Функционала» в 8-битном двоичном коде выглядит так: 0b001nnnxx.

(Здесь указаны значения, используемые для выбора конфигурации и x, обозначает не используемые биты, какое бы у них не было значение, они ни на что не влияют). Бит 4, в данной инструкции, устанавливает способ взаимодействия: 1 – устанавливает 8-битный интерфейс, 0 – 4-битный.

Таким образом, посылая инструкцию 0b00100000 (или 0x20), мы конфигурируем дисплейный модуль на прием команд и символов за два 4-битных посыла, вместо одного 8-битного. Эта команда, должна быть послана первой, что бы мы могли работать с нашей 6-проводной схемой подключения.

В первую очередь устанавливаем значение на шине данных командой P1OUT |= 0x20 (одновременно сбросив RS (значит это команда, а не символ) и сбросив E (необходимо в нашей схеме подключения)), а затем отправляем команду импульсом на E.

Дисплейный модуль не отвечает на команду моментально, есть точные временные интервалы для его корректной работы. В особенности, RS должен быть сброшен в течении определенного времени, до начала импульса на E.

Линии данных должны быть установлены за некоторое время до возникновения спадающего фронта импульса, и должны сохранять свое состояние достаточное время после импульса. Затем, некоторое определенное время должно пройти до того, как мы сможем послать импульс на E снова.

К счастью для нас, точность временной задержки важна только между командными импульсами. Остальные временные задержи, порядка нескольких сотен наносекунд, и скорость выполнения команд MSP430 достаточно небольшая, для того, что бы эти задержки возникали естественным образом.

Время, необходимое для завершения посыла команды, прежде чем можно посылать следующую, должно быть порядка 150 мс. Его можно получить через команды задержки delay().

Резюмируя все сказанное выше, вот набор инструкций для установки ЖК-модуля в 4-битный режим:__delay_cycles(10000); // ожидание на «разогрев» дисплея, сразу после включения P1OUT |= 0x20; // команда переключиться в 4-битный режим P1OUT |= BIT3; // устанавливаем вывод E __delay_cycles(200); P1OUT &= ~BIT3; // сбрасываем вывод E __delay_cycles(200); P1OUT &= 0x0F; // обнуляем 4 старших бита
Хотя установить E можно до установки шины данных, удобней поменять порядок, во избежание временных несовпадений. В случае, если вы используете другой порядок соединения выводов, в особенности если используете несколько портов, этот код не заработает. Это удобно использовать выводы порта P1.4-P1.7 для выводов D4-D7 ЖК-модуля, но не обязательно. Если вы поменяли порядок, например у вас P1.4-P1.7 соединены с D7-D4 соответственно, то вы должны записать 0b0100, а не 0b0010 в шину данных в этом коде. Будьте внимательны, используя другую конфигурацию выводов, вы должны настроить каждый бит шины данных соответственно. Последняя строка обнуляет шину данных, дабы облегчить правильный ввод следующей команды.
Теперь наш дисплей готов принимать команды в 4-битном режиме. Этот режим работает через посылку порции из 4 старших битов по пульсации E. Затем посылки второй порции из 4 младших битов, по второй пульсации. Для нашей схемы соединения мы можем это сделать с помощью такого кода:P1OUT |= ( & 0xF0); // отсылаем старшие 4 бита pulse(); P1OUT &= 0x0F; // обнуляем P1OUT |= (( & 0x0F;) ], и выберете “Link to folder in the filesystem” добавить ссылку на каталог. Потом вы должны найти каталог своей библиотеки и добавить его.

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

(Это то, что мне больше всего не нравится, нужно это делать для каждого нового проекта, и я не нашел способа, как сделать путь к этой папке встроенным по умолчанию, при создании нового проекта CCS).

Итак, в-пятых, кликните правой кнопкой на папке проекта, и выберите “properties” свойства.

Откройте раздел “C/C++ Build” и в “Tool Settings” настройках инструмента, найдите MSP430 Compiler → Include Options, а так же MSP430 Linker → File Search Path. В обоих этих местах, укажите путь к каталогу библиотеки, иначе ваш код не откомпилируется.

Есть один более быстрый путь. В CCS идите в меню Window → Preferences, затем General → Workspace → Linked Resources. Здесь вы можете изменить переменные пути (My_Library и др.) в них может содержаться ссылка на ваш каталог.

Когда вы добавляете новый каталог в проект, вместо поиска папки с библиотеками, можно кликнуть [Variables…] и выбрать нужную переменную из списка.

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

Теперь мы готовы для постройки измерителя ёмкости с блэк-джеком дисплеем. Программа, которую я записал в CMeterLCMG2211.c, демонстрирует несколько новых идей использования ЖК-модуля. Просмотрите код и прочтите комментарии, что бы понять как он работает. Заметьте, что в нем используются команды, подобные MoveCursor(row,col); для управления выводом на дисплей.

Раз библиотека simle_LCM имеет шаблон для вывода строк, что случится, если мы захотим вывести цифровое значение, такое как время задержки таймера (из переменной long int time;)? Один, стандартный для Си метод, это использовать библиотеку “stdio” и функцию sprintf(); из неё.

Все что нам нужно, это создать массив символов, например print_time[10], и использовать sprintf(print_time, “%d”, time); что бы поместить число в строку print_time, а затем передать её в PrintStr() для вывода на экран. К несчастью, этот метод имеет некоторые недостатки, при использовании его для микроконтроллеров.

Во-первых, несмотря на очень хорошую оптимизацию кода компилятором CCS, любая программа использующая функцию printf, получится большой. Наша программа может превысить 2 кБ, доступные в G2211. Во-вторых, оптимизация усложняет получение корректного форматированного вывода.

В идеале, мы должны использовать форматирование %10d, для размещения значения таймера точно в 10 байт переменной print_time. Мы не можем сделать этого с включенной оптимизацией. Мы можем изменить уровень оптимизации для printf в свойствах проекта, но это еще увеличит размер кода.

К счастью, есть методы справиться с этой проблемой. Из переменной типа integer, мы можем вытащить отдельные цифры, используя оператор целочисленного деления и оператор остатка от деления. Так x%10; вернет последнюю цифру числа, хранящегося в x. Затем x/=10; удалит последнюю цифру из числа, оставив остальные.

Запустив цикл из таких операций, до достижения x==0 (больше нет цифр), мы можем извлечь все цифры из числа по одной и послать их на печать.

Кодовая таблица ASCII, используемая в дисплейном модуле, устроена так, что мы можем получить код любой цифры, просто прибавляя её к одной и той же константе, так 0x30+0 будет “0”, 0x30+7 будет “7” и т.д.

Недостаток такого метода с циклом, в том, что мы получаем цифры в обратном порядке, справа налево. У ЖК-модуля есть режим работы, когда он перемещает курсор справа налево после печати символа, таким образом, есть возможность выводить текст в таком порядке. (На самом деле, так работает большинство обычных калькуляторов).

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

Итак, мы смогли создать завершенный измерительный прибор, используя MSP430. Мы использовали комбинацию таймера и компаратора с калиброванным генератором тактового сигнала, для измерения времени задержки в RC-цепи. Дисплей показывает измеренное время в микросекундах.

Зная значение сопротивления R и время, мы можем посчитать реальное значение ёмкости C.

Упражнение: Программа работает прекрасно, но не лучше было бы, имея ЖК-экран, видеть сразу ёмкость вместо времени? Вы можете делать операции с плавающей запятой на MSP430 (хотя неэффективно), но как показать число с плавающей запятой на экране? Если sprintf оказался великоват для нашей программы, то данный функционал, несомненно, займет слишком много памяти. Сможете ли вы вывести ёмкость на экран, не превысив лимит в 2 кБ на G2211? Если у вас не получается, один из способов показан здесь: CMeterLCMFull.c. В этой программе так же реализован авто-выбор единиц измерения. Её код занимает 1934 байта, как раз достаточно, что бы уместиться в G2211.

Примечание переводчика: Чтобы не увеличивать размер текста, я не стал приводить полные листинги, а просто присоединил архив с файлами библиотеки и двумя примерами её использования.

Оригиналы урока на английском: Tutorial 14a: The Alphanumeric LCD и Tutorial 14b: Adding a New Library

Предыдущий урок этого цикла: Урок 13: Комбинируем периферию

Следующий урок этого цикла: Урок 15: Преобразование аналогового сигнала

Источник: http://we.easyelectronics.ru/blog/msp430/2672.html

Alex_EXE

Одним из популярных типов графических дисплеев являются COG (Chip On Glass — кристалл на стекле) дисплеи.

Из-за своих компактных размеров они широко используются в портативных устройствах, имеют небольшое энергопотребление, невысокую цену (если знать, где покупать).

Из недостатков — наличие некоторого количество внешнего обвяза и у большинства мелкий шаг выводов, что неудобства доставит только для начинающих, для портативных устройств это будет даже плюсом.

Подключения дисплея на st7565r к stm32

В принципе к таким дисплеям можно отнести монохромные дисплеи от сотовых телефонов, некоторые из которых рассматривались уже ранее — nokia 3310, 1100, 2760. Но эти дисплеи изготавливались для сотовых телефонов и из этого вытекают некоторые проблемы, из-за чего для изделий массового производства они являются не лучшим вариантом.

Более оптимальным вариантом для серийных устройств будут универсальные серийные дисплеи, к которым можно отнести, например WinStar’овские индикаторы. В статье будет рассмотрен ещё один пример таких индикаторов — ряд графических монохромных COG дисплеев на контроллере ST7565R. А подключать его будем к stm32f103. В работе будет использована библиотека Standard Peripheral Library.

Точнее в примере буду использовать ранее представленную отладочную плату stm32f103c8t6. В качестве главного гостя статьи выступит индикатор на контроллере ST7565R — GS-GG1286456FFWJ-A-R , купленный в местной промэлектронике пару лет назад.

COG LCD GS-GG1286456FFWJ-A-R на ST7565R

Для начала поподробнее рассмотрим их плюсы и минусы.

Плюсы:

  • Компактные. Дисплей при видимой области 47,33х23,65мм имеет размеры 58х39,5х5,1мм + шлейф и провод подсветки.
  • Размеры дисплея GG1286456FFWJ-A-R (из datasheet)

  • Малое энергопотребление. Замеренный ток рабочего дисплея без подсветки 250мкА.
  • Низкая оптовая! цена.
  • Некоторые дисплеи имеют несколько типов интерфейсов, как параллельный, так и последовательный

Минусы:

  • Самый главный минус этих дисплеев, что их можно отнести к специализированным. Главным их потребителем выступают серийные производители. Среди радиолюбителей они не очень распространены. Из этого всего вытекает, что обычным магазинам невыгодно держать такие позиции и их у них в продаже или нет, или т.к. это редкая позиция — у неё высокая цена, в то время, как себестоимость низкая. Т.е. в наших магазинах это редкая и дорогая позиция в розничных отделах, но их можно купить в Китае!
  • За компактность приходится платить некоторым внешним количеством компонентов. В качестве обвязки выступает внешний умножитель напряжения на конденсаторах. Так же отмечаю, что при выборе конденсаторов для этого дисплея смотрите на максимальное их напряжение.
  • Почти у всех дисплеев разная распиновка, следовательно у них плохая взаимозаменяемость.
  • Нет крепежных отверстий.

Плюс/минус:

  • Мелкий шаг. Обычно такие дисплеи имеют гибкий PCB шлейф с шагом 0.5мм. Так же можно встретить шаг 1мм и ещё бывают выводные дисплеи с шагом 1,27мм. Для новичка это минус, для человека с опытом или в серийном устройстве это не имеет значения или плюс.

Так же отмечу, что большое распространение получили модули, которые содержат COG или OLED дисплей установленный на печатную плату с необходимой обвязкой, бонусом идут крепежные отверстия. На плату остается только подать питание и подключить линии данных и управления.

Другие варианты дисплеев на контроллере ST7565R

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

Подключение дисплея GG1286456FFWJ-A-R

Большинство дисплеев имеют несколько вариантов интерфейсов подключения: параллельный 8080, 6800, различные последовательные. В примере будет рассмотрен вариант 8080, т.е.

имеем 8 параллельных линий данных DB0-DB7 и 5 линий управления:
CS — выбор дисплея,
reset — сброс,
A0 или RS — выбор данных или команд,
RW — запись данных в дисплей или чтение
и RD (E) — сигнал по которому производится операция чтения/записи данных в дисплей. При необходимости некоторыми линиями данных можно пренебречь: CS, RW и крайнем случае сбросом; если только в проекте используется всего один дисплей и он один сидит на линиях управления, данные из дисплея не считываются, и во время работы не нужен аппаратный сброс дисплея.

Дисплей питается от 3.3В, как сам, так и его светодиодная подсветка. Потребляемый ток около 250мкА со скачками до 500мкА, что достаточно экономично. Дисплей будем подключать к микроконтроллеру stm32f103c8t6, который питается то же от 3.3В, значит ни каких согласующих элементов не нужно.

Схема

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

Печатка

Печатная плата выполнена на односторонним листе стеклотекстолита размерами 50,5х30,5мм. Из компонентов один резистор перемычка (0 Ом) 1206 и 9 конденсаторов 0805 по 1мкФ 25В. Разъём FPC 0.5mm 30P. Контроллер и его блокировочные конденсаторы по 0,1мкФ находятся на отладочной плате.

Организация дисплея

Дисплей имеет разрешение 128х64 точки, но, как и большинство монохромных дисплеев, имеет постраничную организацию.

Организация дисплея

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

То есть для того, что бы закрасить один пиксель по координате X=1 Y=5, нам будет нужно записать первый столбец нулевой страницы целиком X=1 Y=0-7.

Для этого нужно или хранить видео буфер в контроллере; или перед записью считать блок, затем его модифицировать и только потом записать его; или хорошо представлять структуру экрана и учитывать её при выводе надписей, графиков, рисунков… В самом простом — текстовом — варианте работы с такими дисплеями, достаточно использовать шрифт кратный по высоте 8 точкам (1 странице) и выводить его кратно 8 точкам: 0,7,15…

Прошивка/библиотека

Библиотека для работы с дисплеями на контроллере ST7565R по параллельному интерфейсу 8080 в текстовом режиме была написана на основе даташита и исходника идущего с подобным дисплеем от другого производителя. Команды и шрифты были взяты и адаптированы из ранних моих проектов по дисплеям от nokia3310 и 1100.

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

Так же она написана под
семейство контроллеров stm32f1xx, при использовании её на других контроллерах нужно изменить функцию инициализации выводов и define’ы отвечающие за управления выводами.

Библиотека содержит следующий функции:

lcd_init_pins(); Инициализация выводов дисплея
lcd_delay(unsigned long p); Задержка
lcd_write_data(unsigned char dat); отправка данных на дисплей
lcd_write_cmd(unsigned char cmd); Отправка команд
lcd_Initial_Dispay_Line(unsigned char line); Адрес первой строки дисплея
lcd_Set_Page_Address(unsigned char add); Установка строки (заменена lcd_gotoxy)
lcd_Set_Column_Address(unsigned char add); Установка столбца (заменена lcd_gotoxy)
lcd_Power_Control(unsigned char vol); Управление питанием
lcd_Regulor_Resistor_Select(unsigned char r);
lcd_Set_Contrast_Control_Register(unsigned char mod); Установка контрастности дисплея
lcd_init(void); Инициализация дисплея
lcd_clear(void); Очистка дисплея

Далее идут команды работы с текстом на дисплее. Напоминаю, что дисплей имеет разрешение 128х64, размер символа 6х8, следовательно на дисплей помещается 8 строк по 21 символу.

lcd_gotoxy(unsigned char x,unsigned char y); Установка текстового курсораx — столбец, y — строка (страница)
unsigned char lcd_symbol_decode(unsigned char c); Декодирование сжатой ASCII таблицыc — код символа в ASCII
lcd_putch(unsigned char c); Вывод символа на дисплейc — символ
lcd_putch_inv(unsigned char c); Вывод инвертированного (закраска) символаc — символ
lcd_puts(char *s); Вывод строкиs — строка
lcd_puts_inv(char *s); Вывод инвертированной строкиs — строка
void lcd_test(void); Тестовое заполнение дисплея подряд идущим символами
lcd_putch_big_prototype(unsigned char col,unsigned char row,char c, unsigned char inv); Вывод символов х2 х4 х8 размераcol — ширинаrow — высотаc — символinv — инверсия 0 — выкл, 1 -вкл
lcd_putch_big(char c); Вывод символа размера х2c — символ
lcd_puts_big(char *s); Вывод строки х2s — строка
lcd_puts_int2(unsigned char v); Вывод числа из двух цифр (простая функция)v — число от 0 до 99
lcd_puts_int(int v); Вывод числа.v — число от -32768 до 32767
lcd_puts_long(unsigned long v); Вывод длинного 4 Байтового числа (внимание! функция занимает много памяти)v — число от -2147483648 до 2147483647

Инициализация выводов дисплея производиться путём настройки следующих define’ов в файле ST7565R.h , для stm32f1xx контроллеров.

#define INVERT_MODE 1 // перевернуть дисплей #define lcd_port_data GPIOB // порт линий данных #define lcd_port_data_rcc RCC_APB2Periph_GPIOB // тактирование порта линий данных #define lcd_port_data_offest 0 // смещение, если начальный вывод не 0 #define lcd_pins_data GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; // линии данных, должны идти подряд по возрастающей #define lcd_port_control GPIOB // порт линий команд #define lcd_port_control_rcc RCC_APB2Periph_GPIOB // тактирование порта линий команд #define lcd_pin_RS GPIO_Pin_14 // линия выбора команды/данные #define lcd_pin_RW_WR GPIO_Pin_13 // линия чтение/запись #define lcd_pin_E_RD GPIO_Pin_12 // линия enable, разрешения #define lcd_pin_CS1 GPIO_Pin_11 // линия выбора кристала/дисплея #define lcd_pin_RST GPIO_Pin_15 // линия сброса

Если семейства контроллера отличается, то нужно будет подправить настройку выводов МК функция в файле ST7565R.c : lcd_init_pins, функции вывода данных и команд — lcd_write_data, lcd_write_cmd , а так же define управляющих линий в ST7565R.h .

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

init(); // инициализация контроллера GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET); // включить светодиод delay_ms(100); // задержка 100 мс lcd_init_pins(); // инициализация выводв LCD delay_ms(100); lcd_init(); // инициализация LCD delay_ms(100); GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET); // выключить светодиод lcd_clear(); // очистка дисплея lcd_gotoxy(0,0); // установить курсора по координатам x=0 , y=0 lcd_puts(“COG”); // вывод строки lcd_gotoxy(3,0); // установить курсора по координатам x=3 , y=0 lcd_puts_big(“LCD128x64”); // вывод строки шрифтом x2 lcd_gotoxy(0,2); // установить курсора по координатам x=0 , y=2 lcd_puts(“GS-GG1286456FFWJ-A-R”); lcd_gotoxy(0,3); lcd_puts(“controller ST7565R on”); lcd_gotoxy(0,4); lcd_puts(“mc stm32f103c8t6”); lcd_gotoxy(0,5); lcd_puts_big(“Alex_EXE”); lcd_gotoxy(10,7); lcd_puts(“alex-exe.ru”);

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

Скачать библиотеку ST7565R
Скачать проект под CooCox
Скачать печатку в sprint layout 5

Статья обновлена 23.04.2016

Источник: https://alex-exe.ru/radio/stm32/connect-cog-lcd-st7565r/

бЛог инженера

Какое-то время назад купил я себе такой вот индикатор:

Продаётся он здесь, стоит около 6$, относительно недорогой и простой в использовании. Этот ЖК-индикатор от телефона Nokia 5110, уже распаян на плату со штырьковым разъёмом для подключения к контроллеру.

ЖК-дисплей уже изучен вдоль и поперёк, для него можно найти кучу проектов как для arduino, так и для других контроллеров, в том числе и msp430 (launchpad).

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

ЖК-дисплей от Nokia 5110 сделан на контроллере PCD8544, такой же контроллер используется например в телефоне Nokia 3310.

PCD8544 — микромощный контроллер ЖК-индикаторов, предназначен для вывода на графические дисплеи размером 48 точек в строках на 84 точки в столбцах, имеет всё необходимое для вывода графики и другой информации, в том числе формирователь напряжения питания индикатора.

Общается PCD8544 с управляющим контроллером с помощью последовательной шины SPI, управление по шине осуществляется с частотой до 2МГц, для работы PCD8544 достаточно напряжения питания всего 2В, возможна работа и при более низком напряжении, но с его снижением резко падает контраст на дисплее.

Библиотеки для работы с этим ЖК-индикатором:

Nokia 5110 RobG
Nokia 5110 C Класс-шаблон
Вольт-  Ампер- ватт- метр

Это лишь три из многих библиотек, найденных в интернетах для msp430. Я решил попробовать для начала библиотеку от RobG, так как она в отличие от многих других, использует аппаратную, а не программную реализацию SPI в msp430g2553 и аналогичных, рекомендую для начала почитать оригинальное описание библиотеки по вышеуказанной ссылке, весьма познавательно, правда на английском языке.

Nokia LCD

Для начала желательно хоть немного разобраться, как работает контроллер индикатора перед использованием библиотеки, кроме того это может быть полезно для изменения или дописания библиотеки. Даташит на индикатор:

На картинке видно, как организована адресация каждого пикселя индикатора. Всего у нас 84х48 пикселей, организованных в 6 горизонтальных банков ( от нуля до пяти) и 84 столбцов. Каждый банк содержит 8 пикселей, которые в сумме дают 48 строк.

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

При использовании библиотеки от RobG, на самом деле не обязательно всё это знать, но это необходимо для понимания того, как создаются символы на экране, если понадобится создавать свои графические или текстовые символы, или шрифт.

Подключаем дисплей к микроконтроллеру:

Что меня радует в микроконтроллерах — так это то, что для удобства монтажа и разводки печатной платы, можно легко менять назначения некоторых пинов, просто меняя их описание в программе. Главное — не перепутать потом и не забыть

Источник: http://www.shelezyakin.ru/connection-indicator-from-phone-nokia-5110/

Урок 3. Как подключить ЖК(LCD) дисплей к AVR микроконтроллеру

Мы научились: управлять микроконтроллером и управлять чем то, при помощи микроконтроллера. Теперь, чтобы сделать наше устройство более дружелюбным, будем к нему подключать дисплей.

Сразу оговорюсь дисплей — символьный. Это значит что внутри у него, в памяти, уже есть алфавит. Все что нам нужно — дать команду вывести строку.

Дисплеи бывают разные: разный цвет подсветки экрана, разное количество строк, разное количество символов в строке. Поэтому, здесь рассматривается дисплей WH0802A-YGK-CT, 2 строки по 8 символов, подсветка желтая светодиодная.

https://www.youtube.com/watch?v=cCiYBnVlHfM

Создадим проект в CodeVision. На вкладке LCD укажем порт, к которому будет подключен наш дисплей (PORTD). В строке Char/Line указываем количество символов нашего ЖК дисплея (8).

Генерируем, сохраняем проект. Приводим код к следующему виду:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include
 
#asm
.equ __lcd_port=0x12 ;PORTD
#endasm
#include
 
void main(void)
{
PORTD=0x00;
DDRD=0x00;
lcd_init(8);
 
while (1)
{
 
};
}

#include #asm .equ __lcd_port=0x12 ;PORTD #endasm #include void main(void) { PORTD=0x00; DDRD=0x00; lcd_init(8); while (1) { }; }

Добавились новые строчки

#asm .equ __lcd_port=0x12#endasm Дисплей подключен к PORTD
#include Библиотека для работы с LCD дисплеями

Немного изменим код нашей программы:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include
 
#asm
.equ __lcd_port=0x12
#endasm
#include
 
void main(void)
{
 
PORTD=0x00;
DDRD=0x00;
 
lcd_init(8);
 
lcd_gotoxy(0,0);
lcd_putsf(“lesson3”);
 
#pragma rl+
lcd_gotoxy(0,1);
lcd_putsf(“Урок3”);
#pragma rl-
 
while (1)
{
 
};
}

#include #asm .equ __lcd_port=0x12 #endasm #include void main(void) { PORTD=0x00; DDRD=0x00; lcd_init(8); lcd_gotoxy(0,0); lcd_putsf(“lesson3”); #pragma rl+ lcd_gotoxy(0,1); lcd_putsf(“Урок3”); #pragma rl- while (1) { }; }

lcd_gotoxy(0,0); Переставить курсор в координату ХУ,х – позиция по горизонтали,у – по вертикали
lcd_putsf(«lesson3»); Вывести слово lesson3 на LCD дисплей
#pragma rl+ lcd_putsf(«Урок3»);#pragma rl- Данная директива позволяет вывести на экран русский алфавит, при условии что дисплей его поддерживает

Запустим получившийся код на симуляцию в ISIS Proteus. Как видно первая строчка отображается правильно, а вот вторая кракозябами. Дело в том, что протеус не распознает русский алфавит и если ваш дисплей не будет поддерживать его, то на реальном дисплее тоже будут непонятные символы.

Теперь нужно опробовать все это на настоящем дисплее. Тут есть свои нюансы. Открываем даташит на наш дисплейчик и видим такую вот таблицу с распиновкой:

Наверное, тут все очевидно, но все же:

1 — Земля 0В.

2 — Питание +5В.

3 — Управление контрастностью. Подключается  через переменный резистор.

Светодиодная подсветка. Подключаем как обычный светодиод.

А — подключаем к «+» через токоограничивающий резистор, К — подключаем к «земле» (GND).

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

Внешний вид прошитого устройства

Файл прошивки и протеуса доступны тут

Источник: http://avr-start.ru/?p=296

AVR для начинающих. Урок 7. Подключение LCD

Урок 7

Добрый день, уважаемые читатели!

Настало время подключить к нашему микроконтроллеру экран, который позволит отображать различную информацию. Для данной цели прекрасно подойдет ЖКИ на базе контроллера HD44780, например WH1601, компании WINSTAR.

Стоимость данных ЖКИ достаточно низкая, что позволяет использовать их в любительских проектах. Данный дисплей может отображать одну строку из 16 символов. Так же существуют модели, отображающие 2 строки по 16 символов, 2 строки по 8 символов, и множество других. Управление дисплеем происходит посредством передачи команд и данных от управляющего микроконтроллера — контроллеру дисплея.

Назначение 16 выводов дисплея WH1601:

  • VSS – 0 питания, земля.
  • Vdd — +5 Вольт питания.
  • V — Вывод настройки контрастности дисплея, путем подачи напряжения от 0 до напряжения питания.
  • RS — Если на выводе RS логическая “1” передаются данные, если логический “0” передается команда.
  • R/W — Направление передачи. При R/W =”1” происходит чтение из дисплея, при R/W = “0”, происходит запись в дисплей.
  • E — При переключении логического уровня на данной линии, дисплей производит цикл чтения/записи данных представленных на выводах DB0-DB7.
  • DB0-DB7 — Выводы данных. Данными выводами мы кодируем байт для передачи дисплея, либо декодируем байт, принятый от дисплея. Если DBx=”1” данный бит равен единице, при DBx=”0 ” бит равен нулю.
  • A — Анод светодиода подсветки экрана.
  • K — Катод светодиода подсветки экрана.

Передача данных происходит следующим образом:

1.Устанавливаем логическую единицу на RS, чтобы указать контроллеру о передаче данных.

2.Устанавливаем логический ноль на линии R/W, так как направление передачи — к дисплею.

3.Выставляем байт данных на линии DB0-DB7.

4.Подаем логическую единицу на линию E, на 60 миллисекунд, затем подаем на линию логический ноль.

Читайте также  Стабилизаторы напряжения 5в.

Тем самым мы записываем байт данных в соответствующую память DDRAM,CGROM или CGRAM. Рассмотрим каждый из видов памяти подробнее:

DDRAM — память выделенная под хранение символов на экране. Всё что записывается в этой памяти, мгновенно выводится на экран. Запись символов необходимо производить в ASCII коде.

CGROM— память выделенная под хранение таблицы символов. При записи байта в DDRAM, соответствующий символ находится в данной таблице и выводится на экран.

CGRAM— память выделенная для хранения пользовательских символов. Если Вам необходимо вывести на экран символ, которого нет в стандартной таблице, Вы можете самостоятельно нарисовать его, и поместить в данную таблицу. В данном уроке рассматриваться не будет.

Система команд:

Кроме передачи данных, необходимо подавать специальные команды дисплею. Например, выбор памяти, очистка экрана, изменение позиции курсора, и так далее. Контроллер HD44780 имеет следующую таблицу команд:

Данная таблица нуждается в некотором пояснении.

Рассмотрим формирование команды по данной таблице на примере команды сдвига курсора/экрана:

Первым делом записывается номер команды, затем задаются параметры(см. таблицу выше), а после могут идти незначащие биты.

Передача команды происходит по следующему алгоритму:

1.Устанавливаем логический ноль на RS, чтобы указать контроллеру о передаче команды.

2.Устанавливаем логический ноль на линии R/W, так как направление передачи — к дисплею.

3.Выставляем байт команды на линии DB0-DB7.

4.Подаем логическую единицу на линию E, на 60 миллисекунд, затем подаем на линию логический ноль.

Например, рассмотрим последовательность команд, реализующую следующий алгоритм:

  1. Инициализация дисплея.

  2. Очистка содержимого.

  3. Вывод на экран символа ‘H’.

Для реализации данного алгоритма подадим на контроллер следующую последовательность команд:

*Перед передачей команд установить R/W =0, RS=0

Читайте также  Bluetooth модуль HC-05 для AVR.

Команда 001 ”Определение параметров развертки и ширины шины данных”.

  • DL = 1 — ширина шины данных – 8бит.
  • N = 0 — одна строка символов.
  • F = 0 — матрица символов 5×8 точек.

Команда 00000001 “Очистка экрана, сброс текущего адреса AC”.

Команда 00001 “Выбирается режим отображения”

  • D = 1 — Экран включен.
  • С=0 — Курсор в виде прочерка выключен.
  • И=0 — Курсор в виде мерцающего знакоместа выключен.

Перед передачей символа установить R/W =0, RS=1

Передача символа ‘H’ в память DDRAM.

В качестве примера соберем простейшее устройство инициализирующее ЖКИ, и выводящее строку “Hi!” на него.

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

Соберем простую схему:

Линия RW соединена с землей, так как сейчас мы не планируем читать данные с дисплея, мы будем лишь записывать.

Код прошивки на Си:

void Send_Byte (char Data)void Send_Str (char* str,char length)for (int i = ;i

Источник: http://mkprog.ru/avr/avr-dlya-nachinayushhih-urok-7-podklyuchenie-lcd.html

Подключение LCD дисплея к микроконтроллеру AVR

Читать все новости ➔

Если в каком-либо проекте на микроконтроллере необходим LCD дисплей, то проще всего применить символьные дисплеи на основе контроллера HD44780. О подключении таких дисплеев к микроконтроллеру AVR и пойдёт речь в этой статье. Дисплеев на основе контроллера HD44780 существует много.

О том, какой контроллер стоит в том или ином дисплее можно посмотреть в даташите на дисплей. Я использую дисплеи фирмы Winstar. Различаются эти дисплеи в основном количеством символов в строке, количеством самих строк и наличием подсветки. Определить сколько строк и по сколько символов имеет дисплей можно по названию.

Например, дисплей WH0802A имеет 2 строки по 8 символов, а WH1602 – 2 строки по 16 символов.

Подключение к микроконтроллеру.

Интерфейс у таких дисплеев параллельный, но есть возможность сократить количество используемых выводов микроконтроллера, подключив дисплей не по 8-ми битной, а по 4-х битной шине. При этом, кроме 4-х выводов данных нужно будет подключить ещё сигнал E и RS.

Вывод RW нужен для того, чтобы контроллер дисплея мог определить, записываем или считываем мы с него данные. Если на нём 0 – значит запись, а 1 – чтение. Поскольку читать какие-либо данные из дисплея нам вряд ли придётся, его можно просто соединить с землёй. В общем, вот схема включения: Потенциометром R2 задаётся контрастность дисплея.

Выводы А и К – Анод и Катод светодиодной подсветки соответственно. Катод нужно подключить к земле, а анод либо через резистор 100 Ом к питанию, либо подключить его к ШИМ выводу микроконтроллера – тогда можно будет менять яркость подсветки прямо из программы. Также нужно сказать, что подсветка есть не у всех дисплеев.

О том, есть ли подсветка в дисплее и какая у него распиновка можно посмотреть в даташите на конкретный дисплей. Скачать его можно на сайте производителя – winstar.com.tw.

Софт.

Для работы с такими дисплеями я использую библиотеку от Radosław Kwiecień. Отличная библиотека! Работает с дисплеем по 4-х битной шине и, что очень хорошо, работает из Proteus’a. У этой либы есть следующие полезные подпрограммки:

  • LCD_init –  инициализация дисплея. Достаточно просто вызвать эту подпрограмму в начале проги и дисплей будет инициализирован.
  • LCD_WriteCommand – отправить команду дисплею. Сам код команды загружается в регистр R16. Коды команд можно найти в даташите на дисплей. Вот, например, код очистки дисплея: 0×01
  • LCD_WriteData – запись данных в дисплей. Данные – символы, которые выводятся на дисплей. Символы загружаются в R16 в виде ASCII кода, но тут есть небольшая проблема. Дело в том, что просто записать символ в ASCII можно только если он(символ) английский, либо это цифра. Если же символ русский, придётся записывать его шестнадцатеричный код. Получить его можно с помощью конвертеров, например, этого.
  • LCD_SetAddressDD – установить адрес в памяти данных дисплея. Начиная с него будет производится запись символов на экран. Всего там 80 ячеек (по 40 на каждую строку). С нулевой ячейки начинается первая строка, а с 40-ой – вторая. После инициализации, либо очистки дисплея запись будет производится с 0-го адреса и после записи символа, адрес автоматически увеличивается на 1. Поскольку символов в строке всего 16, то дисплей можно “сдвигать” относительно ячеек памяти, делается это посредством специальной команды, о которых я расскажу чуть позже. Адрес записывается перед вызовом подпрограммы в регистр R16.

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

Итак, прежде чем подключить данную библиотеку к проекту, нужно скопировать её в папку с проектом. Скачать библиотеку можете на сайте автора, а можете у меня. Я слил всю библиотеку в один файл и теперь к проекту её можно подключить одной строчкой кода.

Для этого, где-нибудь в конце программы, в области подпрограмм нужно вписать вот такую строчку:

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

8000000 – тактовая частота микроконтроллера в Герцах. Также необходимо в начале библиотеки определить, на каких портах микроконтроллеру будут линии данных. Итак, открываем файл hd44780.asm и в начале там будут такие строчки:

LCD_PORT, LCD_DDR, LCD_PIN – порт, регистр направления порта и пин того порта, к которому будут подключены выводы данных дисплея (я подключал к порту А), а все остальные определения – номера битов порта, к которым будут подключены конкретные выводы.

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

Итак, вот список интересующих нас команд.

  • 00000001 – очистка дисплея. При подаче этой команды содержимое памяти данных зануляется.
  • 0001xy00 – сдвиг курсора или экрана. Передав эту команду, мы сдвигаем курсор или экран на 1 ячейку памяти. Также у дисплея есть понятие курсора – ячейки, в которую будет произведена запись. Если немного изменить настройки инициализации дисплея, можно сделать так, чтобы на экране появился курсор (в виде мигающего квадратика). Так вот, бит x определяет что мы будем сдвигать – экран(1) или курсор(0), а бит y – направление – влево(0) или вправо(1).
  • 00000010 – сброс сдвигов.

А ниже приведены команды, необходимые для настройки и инициализации дисплея:

  • 000001xy – этой командой можно настроить сдвиг курсора и экрана.  x – сдвиг курсора. 0 – влево, а 1 – вправо. Поскольку мы читаем слева направо, то нам нужно устанавливать здесь 1. y – если здесь установить 1, то при записи нового байта будет автоматически сдвигаться экран.
  • 00001xyz – настройка режима отображения. Бит x отвечает за включение дисплея. Если туда записать 1 – дисплей включится, а если 0 – нет. Если установить бит y в 1, то на дисплее появится курсор в виде прочерка, а если установить в 1 бит z, то курсор будет в виде мигающего чёрного квадратика.
  • 001xyz00 –  с помощью этом команды можно настроить ширину линии данных(4 или 8 бит), размер символа и количество строк. Если бит x установить в 1, то ширина шины данных будет 8 бит, а если 0 – 4 бита. Бит y отвечает за число  строк. Если поставить в 1, то будет активно 2 строки, а если в 0 – одна строка. Бит z, в свою очередь, отвечает за размер символа (0 – 5×8(используется чаще всего), 1 – 5×10).

Изменив эти команды в подпрограмме инициализации библиотеки, можно изменить настройки дисплея. Пример. Для этой статьи я написал небольшую программку – примерчик. Всё что она делает – выводит на дисплей две строчки символов. Используемый микроконтроллер – ATmega16.

Скачать программку можно по ссылке в конце статьи. Текст программы хорошо прокомментирован, поэтому, думаю, всё в ней будет понятно.   UPD #1 По просьбе  Wixa выкладываю код для создания своих символов на дисплее.

Всё прокомментировано, поэтому, я думаю, проблем возникнуть не должно.

ldi r16,0b01010000 rcall LCD_WriteCommand Первые два байта 01 – код команды, а последующие – Адрес в двоичке. К примеру, 000001 – означает 1. 000010 – 2. В данном случае адрес = 16(2-й символ) Всего у нас 64 байта памяти. Каждый байт кодирует содержимое одной строки точек Размер символа у нас 5Х8, пожтому строчек 8, то есть, для того, Чтобы кодировать один символ нам понадобится 8 сток = 8 байт памяти. Старшие три бита каждой строки не используются. А всего в памяти может быть 8 символов(64/8). При записи в память символа нужно указывать адрес последней строчки Символа(64-0), а при выводе – адрес символа. Он может быть от 0 до 8 Опять же – в двоичке. В данном случае адрес посл. строчки = 16, следовательно адрес символа = 2 После передачи команды нужно передать содержание строчек, вот оно: (Помним, что первые три бита не используются) ldi r16,0b00000001 rcall LCD_WriteData ldi r16,0b00000010 rcall LCD_WriteData ldi r16,0b00000100 rcall LCD_WriteData ldi r16,0b00001000 rcall LCD_WriteData ldi r16,0b00011111 rcall LCD_WriteData ldi r16,0b00000010 rcall LCD_WriteData ldi r16,0b00000100 rcall LCD_WriteData ldi r16,0b01000000 rcall LCD_WriteData ;Всё, запись содержания строчек закончена. Далее посылаем команду ; Установки адреса в DDRAM на 1 позицию. ldi r16,0b10000000 rcall LCD_WriteCommand ldi r16,14;Выводить символ будем на 14-ю позицию rcall Lcd_SetAddressDD ldi r16,0b00000010; А тут выводим символ на дисплей rcall LCD_WriteData Поскольку адрес конца строчек = 16, адрес символа = 2(10 в двоичке); Переводить символы из двоички в десятучку можно при помощи инженерного калькулятора в Windows.

Этот код работает, естественно, только после инициализации дисплея. Выводит какое-то подобие молнии. Художник из меня никакой, так что извиняйте. Код в архиве, а также модель в Протеусе обновлена.

Скачать библиотеку + пример.

Возможно, Вам это будет интересно:

Источник: http://meandr.org/archives/5130

Ссылка на основную публикацию
Adblock
detector
",css:{backgroundColor:"#000",opacity:.6}},container:{block:void 0,tpl:"
"},wrap:void 0,body:void 0,errors:{tpl:"
",autoclose_delay:2e3,ajax_unsuccessful_load:"Error"},openEffect:{type:"fade",speed:400},closeEffect:{type:"fade",speed:400},beforeOpen:n.noop,afterOpen:n.noop,beforeClose:n.noop,afterClose:n.noop,afterLoading:n.noop,afterLoadingOnShow:n.noop,errorLoading:n.noop},o=0,p=n([]),h={isEventOut:function(a,b){var c=!0;return n(a).each(function(){n(b.target).get(0)==n(this).get(0)&&(c=!1),0==n(b.target).closest("HTML",n(this).get(0)).length&&(c=!1)}),c}},q={getParentEl:function(a){var b=n(a);return b.data("arcticmodal")?b:(b=n(a).closest(".arcticmodal-container").data("arcticmodalParentEl"),!!b&&b)},transition:function(a,b,c,d){switch(d=null==d?n.noop:d,c.type){case"fade":"show"==b?a.fadeIn(c.speed,d):a.fadeOut(c.speed,d);break;case"none":"show"==b?a.show():a.hide(),d();}},prepare_body:function(a,b){n(".arcticmodal-close",a.body).unbind("click.arcticmodal").bind("click.arcticmodal",function(){return b.arcticmodal("close"),!1})},init_el:function(d,a){var b=d.data("arcticmodal");if(!b){if(b=a,o++,b.modalID=o,b.overlay.block=n(b.overlay.tpl),b.overlay.block.css(b.overlay.css),b.container.block=n(b.container.tpl),b.body=n(".arcticmodal-container_i2",b.container.block),a.clone?b.body.html(d.clone(!0)):(d.before("
"),b.body.html(d)),q.prepare_body(b,d),b.closeOnOverlayClick&&b.overlay.block.add(b.container.block).click(function(a){h.isEventOut(n(">*",b.body),a)&&d.arcticmodal("close")}),b.container.block.data("arcticmodalParentEl",d),d.data("arcticmodal",b),p=n.merge(p,d),n.proxy(e.show,d)(),"html"==b.type)return d;if(null!=b.ajax.beforeSend){var c=b.ajax.beforeSend;delete b.ajax.beforeSend}if(null!=b.ajax.success){var f=b.ajax.success;delete b.ajax.success}if(null!=b.ajax.error){var g=b.ajax.error;delete b.ajax.error}var j=n.extend(!0,{url:b.url,beforeSend:function(){null==c?b.body.html("
"):c(b,d)},success:function(c){d.trigger("afterLoading"),b.afterLoading(b,d,c),null==f?b.body.html(c):f(b,d,c),q.prepare_body(b,d),d.trigger("afterLoadingOnShow"),b.afterLoadingOnShow(b,d,c)},error:function(){d.trigger("errorLoading"),b.errorLoading(b,d),null==g?(b.body.html(b.errors.tpl),n(".arcticmodal-error",b.body).html(b.errors.ajax_unsuccessful_load),n(".arcticmodal-close",b.body).click(function(){return d.arcticmodal("close"),!1}),b.errors.autoclose_delay&&setTimeout(function(){d.arcticmodal("close")},b.errors.autoclose_delay)):g(b,d)}},b.ajax);b.ajax_request=n.ajax(j),d.data("arcticmodal",b)}},init:function(b){if(b=n.extend(!0,{},a,b),!n.isFunction(this))return this.each(function(){q.init_el(n(this),n.extend(!0,{},b))});if(null==b)return void n.error("jquery.arcticmodal: Uncorrect parameters");if(""==b.type)return void n.error("jquery.arcticmodal: Don't set parameter \"type\"");switch(b.type){case"html":if(""==b.content)return void n.error("jquery.arcticmodal: Don't set parameter \"content\"");var e=b.content;return b.content="",q.init_el(n(e),b);case"ajax":return""==b.url?void n.error("jquery.arcticmodal: Don't set parameter \"url\""):q.init_el(n("
"),b);}}},e={show:function(){var a=q.getParentEl(this);if(!1===a)return void n.error("jquery.arcticmodal: Uncorrect call");var b=a.data("arcticmodal");if(b.overlay.block.hide(),b.container.block.hide(),n("BODY").append(b.overlay.block),n("BODY").append(b.container.block),b.beforeOpen(b,a),a.trigger("beforeOpen"),"hidden"!=b.wrap.css("overflow")){b.wrap.data("arcticmodalOverflow",b.wrap.css("overflow"));var c=b.wrap.outerWidth(!0);b.wrap.css("overflow","hidden");var d=b.wrap.outerWidth(!0);d!=c&&b.wrap.css("marginRight",d-c+"px")}return p.not(a).each(function(){var a=n(this).data("arcticmodal");a.overlay.block.hide()}),q.transition(b.overlay.block,"show",1*")),b.overlay.block.remove(),b.container.block.remove(),a.data("arcticmodal",null),n(".arcticmodal-container").length||(b.wrap.data("arcticmodalOverflow")&&b.wrap.css("overflow",b.wrap.data("arcticmodalOverflow")),b.wrap.css("marginRight",0))}),"ajax"==b.type&&b.ajax_request.abort(),p=p.not(a))})},setDefault:function(b){n.extend(!0,a,b)}};n(function(){a.wrap=n(document.all&&!document.querySelector?"html":"body")}),n(document).bind("keyup.arcticmodal",function(d){var a=p.last();if(a.length){var b=a.data("arcticmodal");b.closeOnEsc&&27===d.keyCode&&a.arcticmodal("close")}}),n.arcticmodal=n.fn.arcticmodal=function(a){return e[a]?e[a].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof a&&a?void n.error("jquery.arcticmodal: Method "+a+" does not exist"):q.init.apply(this,arguments)}}(jQuery)}var debugMode="undefined"!=typeof debugFlatPM&&debugFlatPM,duplicateMode="undefined"!=typeof duplicateFlatPM&&duplicateFlatPM,countMode="undefined"!=typeof countFlatPM&&countFlatPM;document["wri"+"te"]=function(a){let b=document.createElement("div");jQuery(document.currentScript).after(b),flatPM_setHTML(b,a),jQuery(b).contents().unwrap()};function flatPM_sticky(c,d,e=0){function f(){if(null==a){let b=getComputedStyle(g,""),c="";for(let a=0;a=b.top-h?b.top-h{const d=c.split("=");return d[0]===a?decodeURIComponent(d[1]):b},""),c=""==b?void 0:b;return c}function flatPM_testCookie(){let a="test_56445";try{return localStorage.setItem(a,a),localStorage.removeItem(a),!0}catch(a){return!1}}function flatPM_grep(a,b,c){return jQuery.grep(a,(a,d)=>c?d==b:0==(d+1)%b)}function flatPM_random(a,b){return Math.floor(Math.random()*(b-a+1))+a}