Светодиодный дисплей 7×7 на микроконтроллере avr

AVR. Учебный курс. Подключение к AVR LCD дисплея HD44780

Сегодня разменял четверть века!

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

О том как подключить к AVR LCD дисплей я вам сейчас и поведаю.

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

Продается везде где только можно, стоит недорого (8х2 мне обошелся порядка 150 рублей), а также под него написана куча кода. Я же, как обычно, решил изобрести велосипед и сварганить свою собственную тру-библиотеку для работы с этим типом индикаторов. Разумеется на ассемблере, а на чем же еще? 😉

Подключение.
LCD на базе HD44780 подключается к AVR микроконтроллеру напрямую к портам. Есть два способа подключения — на 8 бит и на 4 бита. В восьмибитном режиме немножко проще закидывать байты — не нужно сдвигать байт, зато в четырех битном резко нужно тратить на целых четыре ножки контроллера меньше. Есть еще одна особенность работы в 8-битном режиме — к некоторым контроллерам можно подрубить этот дисплей как внешнее ОЗУ и засылать данные простыми командами пересылки. Лично я подключил его в режиме полного порта у меня один фиг выводы уже девать некуда было, так что не жалко.

  • Выводы DB7…DB0 это шина данных/адреса.
  • E — стробирующий вход. Дрыгом напряжения на этой линии мы даем понять дисплею что нужно забирать/отдавать данные с/на шину данных.
  • RW — определяет в каком направлении у нас движутся данные. Если 1 — то на чтение из дисплея, если 0 то на запись в дисплей.
  • RS — определяет что у нас передается, команда (RS=0) или данные (RS=1). Данные будут записаны в память по текущему адресу, а команда исполнена контроллером.

Со стороны питания все еще проще:

Подключение дисплея
Видимая и скрытая область экранной памяти
Структура адресации контроллера HD44780
Формирование символа в ячейке CGRAM

  • GND — минус, он же общий.
  • Vcc — плюс питания, обычно 5V
  • V0 — вход контрастности. Сюда нужно подавать напряжение от нуля до напряжения питания, тем самым задается контрастность изображения. Можно поставить переменный резистор, включенный потенциометром и крутить в свое удовольствие. Главное поймать значение максимального контраста, но чтобы не было видно знакомест (серый ореол из квадратов вокруг символа). Если же выставить слишком малый контраст, то символы будут переключаться лениво и задумчиво. Примерно как в калькуляторе у которого сели батарейки.
  • А — это вход Анода светодиодной подсветки. Короче плюс.
  • К — соответственно Катод, он же минус. Подсветка хавает примерно 100мА и поэтому нужно выставить туда токоограничительный резистор на 100 Ом. Кстати, многие ЖК дисплеи имеют на плате пятачки для припайки резисторов. Если прозвонить, то можно убедиться в том, что эти линии ведут на входы питания LCD, поэтому, впаяв резисторы, можно не заморачиваться на запитку подстветки, она будет подключена к питанию контроллера.

Логическая структура LCD контроллера HD44780

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

DDRAM — память дисплея. Все что запишется в DDRAM будет выведено на экран. То есть, например, записали мы туда код 0x31 — на экране выскочит символ «1» т.к. 0х31 это ASCII код цифры 1.

Но есть тут одна особенность — DDRAM память гораздо больше чем видимая область экрана. Как правило, DDRAM содержит 80 ячеек — 40 в первой строке и 40 во второй, а на дисплей может двигаться по этой линейке как окошко на логарифмической линейке, высвечивая видимую область.

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

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

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

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

Всего в CGRAM может быть 8 символов, соответственно CGRAM имеет 64 байта памяти. Эти программируемые символы имеют коды от 0х00 до 0х07.

Так что, закинув, например, в первые 8 байт CGRAM (первый символ с кодом 00) какую нибудь фигню, и записав в DDRAM нуль (код первого символа в CGRAM) мы увидим на экране нашу хрень.

Доступ к памяти.
Тут все просто. Мы командой выбираем в какую именно память и начиная с какого адреса будем писать. А потом просто шлем байты. Если указано, что записываем в DDRAM то на экран (или в скрытую область) полезут символы, если в CGRAM то байты полезут уже в память знакогенератора. Главное потом не забыть переключится обратно на область DDRAM

Система команд.
Система команд проста как мычание. О том, что передается команда контроллеру дисплея сообщит нога RS=0. Сама команда состоит из старшего бита, определяющего за что отвечает данная команда и битов параметров, указывающих контроллеру HD44780 как дальше жить.

Таблица команд:

DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 Значение
1 Очистка экрана. Счетчик адреса на 0 позицию DDRAM
1 Адресация на DDRAM сброс сдвигов, Счетчик адреса на 0
1 I/D S Настройка сдвига экрана и курсора
1 D C B Настройка режима отображения
1 S/C R/L Сдвиг курсора или экрана, в зависимости от битов
1 DL N F Выбор числа линий, ширины шины и размера символа
1 AG AG AG AG AG AG Переключить адресацию на SGRAM и задать адрес в SGRAM
1 AD AD AD AD AD AD AD Переключить адресацию на DDRAM и задать адрес в DDRAM

Теперь поясню что значат отдельные биты:

  • I/D — инкремент или декремент счетчика адреса. По дефолту стоит 0 — Декремент. Т.е. каждый следующий байт будет записан в n-1 ячейку. Если поставить 1 — будет Инкремент.
  • S — сдвиг экрана, если поставить 1 то с каждым новым символом будет сдвигаться окно экрана, пока не достигнет конца DDRAM, наверное удобно будет когда выводишь на экран здоровенную строку, на все 40 символов, чтобы не убегала за экран.
  • D — включить дисплей. Если поставить туда 0 то изображение исчезнет, а мы в это время можем в видеопамяти творить всякие непотребства и они не будут мозолить глаза. А чтобы картинка появилась в эту позицию надо записать 1.
  • С — включить курсор в виде прочерка. Все просто, записали сюда 1 — включился курсор.
  • B — сделать курсор в виде мигающего черного квадрата.
  • S/C сдвиг курсора или экрана. Если стоит 0, то сдвигается курсор. Если 1, то экран. По одному разу за команду
  • R/L — определяет направление сдвига курсора и экрана. 0 — влево, 1 — вправо.
  • D/L — бит определяющий ширину шины данных. 1-8 бит, 0-4 бита
  • N — число строк. 0 — одна строка, 1 — две строки.
  • F — размер символа 0 — 5х8 точек. 1 — 5х10 точек (встречается крайне редко)
  • AG — адрес в памяти CGRAM
  • АD — адрес в памяти DDRAM

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

Задача:

  1. Включить дисплей.
  2. Очистить содержимое.
  3. Сдвинуть курсор на одну позицию.
  4. И записать туда «1».

Решение (последовательность команд):

Первым делом Инициализация дисплея без которой большая часть дисплеев на HD44780 просто откажется работать. Некоторые виды имеют дефолтные состояние (шина 8 бит, курсор в 0) и им только дисплей включить. Но все же ее лучше сделать, мало ли что там намудрил разработчик. Лишней не будет.

  • 00111000 Шина 8 бит, 2 строки
  • 00000001 Очистка экрана
  • 00000110 Инкремент адреса. Экран не движется
  1. 00001100 Включили дисплей (D=1)
  2. 00000001 Очистили дисплей. Указатель встал на DDRAM
  3. 00010100 Сдвинули курсор (S/C=0) вправо (R/L=1)
  4. 00110001 — это мы уже записали данные (ножка RS=1) код «1» 0х31

Жирным шрифтом выделен идентификатор команды, ну а остальное по таблице увидите.

Задача: создать свой символ. С кодом 01 и вывести его на экран.
Считаем, что дисплей у нас уже инициализирован и готов к приему данных.

Решение:

  1. 01001000      Выбираем в CGRAM адрес 0х08 — как раз начало второго символа (напомню, что на один символ уходит 8 байт)
  2. 00000001     Это пошли 8 байт данных.

    (RS=1)

  3. 00000010     Рисуем значок молнии, ну или
  4. 00000100     ССовскую Зиг руну, кому как
  5. 00001000     больше нравится.

  6. 00011111     Старшие три бита не действуют
  7. 00000010     Туда можно писать что угодно, на
  8. 00000100     результат влиять не будет.

  9. 00001000     Последний байт данных  
  10. 10000000      А это уже команда — переключение адреса на DDRAM и указатель на адрес 0000000 — первый символ в первой строке.
  11. 00000001      И снова данные (RS=1), код 01 — именно в него мы засунули нашу молнию.

Опа и он на экране!

Так, с логикой разобрались, пора вкуривать в физику протокола общения. Код я приведу несколько позже, когда вылижу свою библиотеку и заоптимизирую до состояния идеала. Пока же дам алгоритм, а его уж на любом языке программирования реализовать можно. Хоть на ассемблере, хоть на Сях, да хоть на Васике 🙂

Алгоритм чтения/записи в LCD контроллер HD44780
Направление, а также команда/данные определяются ножками, а чтение и запись осуществляется по переходу строба (вывод Е) из 1 в 0

Инициализация портов

  1. RS, RW, E — в режим выхода.
  2. DB7..DB0 в режим входа. Впрочем, можно их не трогать, дальше переопределим.

Ожидание готовности, чтение флага занятости.

  1. Порт данных на вход с подтяжкой (DDR=0, PORT=1)
  2. RS=0 (команда)
  3. RW=1 (чтение)
  4. E=1 (Готовьсь!!!)
  5. Пауза (14 тактов процессора на 8МГЦ хватало)
  6. Е=0 (Пли!)
  7. Читаем из порта. Если бит 7 (Busy flag) установлен, то повторяем все заново, пока не сбросится.

Запись команды

  1. Ожидание готовности
  2. RS=0 (команда)
  3. RW=0 (запись)
  4. Е=1 (Готовьсь!!!)
  5. Порт на выход
  6. Вывести в порт код команды
  7. Пауза
  8. Е=0 (Пли!)
  9. Орудие на плечо Порт на вход, на всякий случай.

Запись Данных

  1. Ожидание готовности
  2. RS=1 (Данные)
  3. RW=0 (запись)
  4. Е=1 (Готовьсь!!!)
  5. Порт на выход
  6. Вывести в порт код команды
  7. Пауза
  8. Е=0 (Пли!)
  9. Порт на вход, на всякий случай.

Чтение команды

  1. Ожидание готовности
  2. Порт данных на вход с подтяжкой (DDR=0, PORT=1)
  3. RS=0 (команда)
  4. RW=1 (чтение)
  5. Е = 1 (Готовьсь! В этот момент данные из LCD вылазят на шину)
  6. Пауза
  7. Считываем данные с порта
  8. E=0 (Ать!)

Чтение Данных

  1. Ожидание готовности
  2. Порт данных на вход с подтяжкой (DDR=0, PORT=1)
  3. RS=1 (Данные)
  4. RW=1 (чтение)
  5. Е = 1 (Готовьсь! В этот момент данные из LCD вылазят на шину)
  6. Пауза
  7. Считываем данные с порта
  8. E=0 (Ать!)

С четырех разрядной шиной все точно также, только там каждая операция чтения/записи делается за два дрыга строба.

Запись:

  1. E=1
  2. Пауза
  3. Выставили в порт старшую тетраду
  4. E=0
  5. Пауза
  6. Е=1
  7. Пауза
  8. Выставили в порт младшую тетраду
  9. Е=0

Чтение

  1. E=1
  2. Пауза
  3. Читаем из порта старшую тетраду
  4. Е=0
  5. Пауза
  6. Е=1
  7. Пауза
  8. Читаем из порта младшую тетраду
  9. Е=0

Ждите код 🙂 Скоро будет 🙂
UPD:
А вот и код!

Источник: http://easyelectronics.ru/avr-uchebnyj-kurs-podklyuchenie-k-avr-lcd-displeya-hd44780.html

Проекты на микроконтроллерах AVR – Работа с дисплеем 16×2 на контроллере HD44780 в Bascom-AVR

 Работа с дисплеем 16×2 на контроллере HD44780 в Bascom-AVR

 Жидкокристаллические дисплеи на контроллере HD44780 (а также совместимом с ним KS0066) очень распространены благодаря простому методу работы с ними, а так же небольшой цене. В зависимости от исполнения дисплея, они позволяют выводить от 8-и до 40-ка символов в каждой строке, строк может быть одна, две или четыре. Чаще всего встречаются 8*2 (восемь символов*две строки), 16*2 и 20*4.  

 Для примера рассмотрим распиновку индикатора 16*2 (у всех дисплеев на контроллере HD44780 она похожа)

У каждого дисплея на контроллере HD44780 для подключения имеется 14 выводов + 2 вывода для подсветки (если она имеется):

  1. Земля, GND
  2. Напряжение питания, Vcc (+5V)
  3. Настройка контрастности, Vo
  4. Выбор регистра, R/S
  5. Чтение/запись, R/W
  6. Сигнал разрешения чтения/записи, E
  7. Bit 0, D0 
  8. Bit 1, D1
  9. Bit 2, D2
  10. Bit 3, D3
  11. Bit 4, D4 
  12. Bit 5, D5
  13. Bit 6, D6
  14. Bit 7, D7 
  15. Питание подсветки для дисплеев с подсветкой, LED +
  16. Питание подсветки для дисплеев с подсветкой, LED –

Данные в дисплей загружаются по шине данных (D0-D7), при этом контроллер поддерживает как 8-и, так и 4-х битное подключение.

4-х битное подключение экономит ножки микроконтроллера и чаще всего достаточно для многих задач (при 8и битном подключении можно быстрее загружать данные в контроллер дисплея, но нам пока это ни к чему, поэтому не будем его рассматривать). Для 4-х битного подключения используются 4 последних бита шины (D4-D7).

В качестве примера будем использовать дисплей 20х4, подключенный к микроконтроллеру ATmega8 по 4х битному интерфейсу по схеме ниже

 Дисплей требует для питания 5 вольт, делителем на резисторе R1 настраивается контрастность отображаемых символов, вывод R/W подключается к земле (т.е. выбрана постоянная запись в дисплей). Подключать оставшиеся выводы можно к любым свободным ножкам микроконтроллера. Конфигурация ножек для подключения дисплея у микроконтроллера ATmega8 будет выглядеть следующим образом:

$regfile = “m8def.

dat”                        'выбранный тип микроконтроллера
$crystal = 1000000                            'частота работы 1 МГц

Config Lcd = 20 * 4                           'указываем какой у нас дисплей

'и конфигурируем ножки для подключения

Config Lcdpin=Pin,Db4=PortB.3, Db5=PortB.2, Db6=PortB.1, Db7=PortB.0,E=PortB.4,Rs=PortB.5

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

CLS – очистка дисплея

LCD – вывести данные на дисплей (пример: Lcd “Hello world” выведет надпись Hello world)

Locate – установка места на индикаторе с которого начнется выводится текст (пример: Locate 1,5 установит курсор на 5-е знакоместо первой строчки и текст выводимый командой LCD будет начинаться отсюда)

CURSOR ON / OFF / BLINK / NOBLINK – включает или отключает отображение и мигание курсора, по умолчанию он включен (пример: отключим курсор командой Cursor Off)

А теперь напишем вот такую небольшую программку, которая выведет надпись на дисплей:

$regfile = “m8def.

dat”      'выбранный тип микроконтроллера
$crystal = 1000000          'частота работы 1 МГц

Config Lcd = 20 * 4         'указываем какой у нас дисплей
'и конфигурируем ножки для подключения
Config Lcdpin=Pin,Db4=Portb.3, Db5=Portb.2, Db6=Portb.1, Db7=Portb.0,E=Portb.4,Rs=Portb.

5

Cursor Off                  'выключим отображение курсора
Cls                         'очистим дисплей

Lcd “LCD 20*4 HD44780”      'выводим текст в первой строке
Locate 2 , 8                'переводим курсор на вторую строку, восьмое знакоместо
Lcd “AVRproject.

ru”         'выводим текст

End

в результате на дисплее получим следующее:

 Также в Bascom-AVR есть еще несколько дополнительных команд для работы с дисплеями:

UPPERLINE – возвращает курсор на самую верхнюю строчку дисплея.

LOWERLINE – перевод курсора на вторую строку

THIRDLINE – перевод курсора на третью строку

FOURTHLINE – перевод курсора на четвертую строку 

HOME – также возвращает курсор на верхнюю строчку, но в отличии от команды UPPERLINE эта команда может принимать дополнительные значения: если после нее поставить букву L, T или F то курсор переместится в начало строчки, название которой начинается с соответствующей буквы (пример:  для того чтобы переместить курсор в начало третьей строки, нужно написать команду HOME T )

пример кода для вывода информации на дисплей с использованием этих команд:

$regfile = “m8def.

dat”      'выбранный тип микроконтроллера
$crystal = 1000000          'частота работы 1 МГц

Config Lcd = 20 * 4         'указываем какой у нас дисплей
'и конфигурируем ножки для подключения
Config Lcdpin=Pin,Db4=Portb.3, Db5=Portb.2, Db6=Portb.1, Db7=Portb.0,E=Portb.

4,Rs=Portb.

5

Cursor Off                  'выключим отображение курсора
Cls                         'очистим дисплей

Lcd “*** HD44780  LCD ***”  'выводим текст в первой строке
Lowerline                   'переходим на вторую строку
Lcd “Line number 2”         'выводим текст
Thirdline                   'переходим на третью строку
Lcd “AaBbCcDdEeFfGgHfIiJj”  'выводим на третьей строке
Fourthline                  'переходим на четвертую строку
Lcd “1234567890”            'печатаем на четвертой строчке

End                         'конец программы

SHIFTLCD LEFT / RIGHT – сдвигает текст в строке на которой находится курсор на одну позицию влево или вправо. 

SHIFTCURSOR LEFT / RIGHT – сдвигает курсор на одну позицию влево или вправо 

и пример того как использовать сдвиг текста:

$regfile = “m8def.

dat”    'выбранный тип микроконтроллера
$crystal = 1000000        'частота работы 1 МГц

Dim A As Byte             'переменная для организации цикла

Config Lcd = 20 * 4       'указываем какой у нас дисплей
'и конфигурируем ножки для подключения
Config Lcdpin=Pin,Db4=Portb.3, Db5=Portb.2, Db6=Portb.1, Db7=Portb.0,E=Portb.4,Rs=Portb.

5

Cursor Off                'выключим отображение курсора
Cls                       'очистим дисплей

Locate 1 , 11             'устанавливаем курсор на первой строке, десятом знакоместе
Lcd “Bascom-AVR”          'выведем текст

'цикл сдвига влево
For A = 1 To 10           'повторяем этот цикл пока переменная А не достигнет значения 10
 Shiftlcd Left            'сдвинем текст влево
 Waitms 300               'задержка 300 миллисекунд
Next A                    'увеличиваем значение переменной А на 1

'цикл сдвига вправо
For A = 1 To 10           'повторяем цикл пока переменная А не достигнет значения 10
 Shiftlcd Right           'теперь сдвинем текст вправо
 Waitms 300               'задержка 300 миллисекунд
Next A                    'увеличиваем значение переменной А на 1

'продолжаем выполнение  программы
Wait 1                    'задержка 1 секунда

Home F                    'устанавливаем курсор на нижнюю строчку

Lcd “END PROGRAM”         'и выводим надпись

End                       'конец программы

результат на видео ниже:

Источник: http://AVRproject.ru/index/rabota_s_displeem_16x2_na_kontrollere_hd44780_v_bascom_avr/0-52

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 миллисекунд, затем подаем на линию логический ноль.

Читайте также  AVR для начинающих. Урок 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

Читайте также  AVR для начинающих. Урок 4. Тактирование микроконтроллера.

Команда 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

Динамическая индикация на примере управления светодиодной матрицей 8×8 GNM-7881AUE | avr | programming

Чтобы понять, что такое динамическая индикация, и для чего она нужна, нужно рассмотреть для примера промышленный индикатор GNM-7881AUE.

В матрице GNM-7881AUE 64 красных светодиода.

Если выводить из матрицы контакты всех светодиодов для управления каждым по отдельности, то понадобится как минимум 65 внешних контактов на корпусе матрицы, а также микроконтроллер с 64 портами вывода.

Несомненно, это технологически реализовать очень трудно (и нецелесообразно). Поэтому на заводе светодиоды объединили в 8 групп по строкам и столбцам, и соединили их в матрицу следующим образом:

При такой схеме подключения внешних контактов матрицы и портов микроконтроллера потребуется существенно меньше – только 16. Чтобы зажечь, например, светодиод в левом верхнем углу, нужно на контакт 13 матрицы подать плюс, а на контакт 9 минус. Для этого можно использовать, например, порты вывода микроконтроллера ATmega16 или ATmega32 и резистор:

Светодиод слева вверху зажжется, если микроконтроллер на порт PA0 выставит лог. 1 (+5 вольт), а на PB3 лог. 0 (0 вольт).

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

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

ОК, все очень красиво, но как, например, зажечь один светодиод в центре матрицы, оставив остальные при этом выключенными? Или, как, наоборот, зажечь все светодиоды, кроме одного-двух в центре? Понятно, что при такой схеме включения невозможно этого добиться простой подачей на выходные порты ноликов и единичек (с помощью статической индикации). Тут на помощь как раз и приходит динамическая индикация.

[Динамическая индикация]

Название “динамическая” происходит от того, что формирование изображения происходит не статически, а в динамике, т. е. сначала, например, показывают только первый столбец изображения (все остальные столбцы погашены), на втором шаге показывают только второй столбец, и так далее до 8-столбца.

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

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

1. Длительность отображения каждого столбца постоянна, одинакова для всех столбцов.
2. Частота смены столбцов не меняется.

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

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

Если бы у нас резисторы были подключены не к катодам (не к строкам), а к анодам (к столбцам), то тогда развертку изображения надо было делать не по столбцам, по строкам (у нас бежал бы по строкам лог. 0).

Для примера приведу алгоритм отображения цифры 2 (на рисунке светодиоды, которые надо зажигать, я закрасил красным цветом), столбцы и строки нумеруются от 1 до 8:

1. Отображение столбца 1. Для этого на PA0 подаем лог. 1, на PA1..PA7 подаем лог. 0. На порты PB3, PB4, PD0, PD1, PD3, PD5..PD7 также лог. 1. Держим матрицу с таком состоянии 2.5 мс.
2. Отображение столбца 2. Для этого на PA1 подаем лог. 1, на PA0, PA2..PA7 подаем лог. 0. Подаем лог. 1 на PB3, PB4, PD1, PD3, PD7, подаем лог. 0 на PD0, PD5, PD6.

Держим матрицу с таком состоянии 2.5 мс.
3. Отображение столбца 3. Для этого на PA2 подаем лог. 1, на PA0, PA1, PA3..PA7 подаем лог. 0. Подаем лог. 1 на PB3, PD0, PD1, PD5, PD7, подаем лог. 0 на PB4, PD3, PD6. Держим матрицу с таком состоянии 2.5 мс.
4. Отображение столбца 4. Все то же самое, что и на шаге 3, только подаем лог.

1 не на PA2, а на PA3. Держим матрицу с таком состоянии 2.5 мс.
5. Отображение столбца 5. Все то же самое, что и на шаге 4, только подаем лог. 1 не на PA3, а на PA4. Держим матрицу с таком состоянии 2.5 мс.
6. Отображение столбца 6. Все то же самое, что и на шаге 5, только подаем лог. 1 не на PA4, а на PA5. Держим матрицу с таком состоянии 2.

5 мс.
7. Отображение столбца 7. Для этого на PA6 подаем лог. 1, на PA0..PA5, PA7 подаем лог. 0. Подаем лог. 1 на PB3, PB4, PD0, PD3, PD5, PD7, подаем лог. 0 на PD0, PD1, PD6. Держим матрицу с таком состоянии 2.5 мс.
8. Отображение столбца 8. Все то же самое, что и на шаге 1, только подаем лог. 1 не на PA0, а на PA7.

Держим матрицу с таком состоянии 2.5 мс.

Цикл шагов 1..8 занял ровно 20 мс (2.5+2.5+2.5+2.5+2.5+2.5+2.5+2.5). При непрерывном чередовании шагов 12345678123… получится отображение символа 2 без видимого мерцания. По похожему принципу работают все “взрослые” системы индикации в автобусах, электричках, турникетах, рекламных табло.

[Пример управления матрицей LED8X8]

Для экспериментирования со знакогенераторами 8×8 я сделал небольшой проект для отображения символов на индикаторе GNM-7881AUE. Схема подключения индикатора – точно такая же, как используемая при обсуждении динамической индикации. Красными метками я указал номера выходных контактов макетной платы AVR-USB-MEGA16.

Проект управляется через виртуальный COM-порт – в консоли можно было ввести шестнадцатеричный код символа, и он тут же высвечивается на индикаторе. На фото видна макетная плата AVR-USB-MEGA16, на которую припаян индикатор GNM-7881AUE (весь монтаж и резисторы SMD 0805 номинала 150 Ом выполнен с обратной стороны макетной платы).

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

[Что внутри проекта LED8x8]

Проект собран на основе статьи [1]. Скачанный пример дополнен командами, и в главный цикл main добавлена процедура динамической индикации, отображающая символы, бегущую строку или анимацию из картинок BMP.

Питается и конфигурируется устройство от USB.

Когда активен интерфейс USB, то возможно мерцание отображаемой картинки, так как на программную поддержку протокола (библиотека V-USB) тратится большая доля процессорного времени.

В память можно занести любое количество текстов и картинок (пока хватит места в EEPROM), они сохраняются в памяти после выключения питания.

Управление и конфигурирование осуществляется через текстовую консоль, подключенную к виртуальному COM-порту (через любую консоль типа Hyperterminal, Terraterm или putty), интерфейс управления имеет систему подсказок. Вот пример сеанса работы с управляющей консолью проекта:

Тексты можно вводить командой TXT, а BMP-картинки в черно-белом формате 8×8 пикселов можно загрузить по протоколу XMODEM (моя любимая консоль SecureCRT умеет это делать).

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

Скорость бегущей строки и смены картинок меняется командой SPEED (от 1 до 10). Доступны также некоторые отладочные команды.

[Применение матричных индикаторов 5×7 точек]

Для светодиодной матрицы можно применить не только индикаторы 8×8 точек, но также и индикаторы 5×7 точек, которые иногда проще найти и купить. К примеру, есть индикаторы TFB2457C, TFB2757C, которые хороши тем, что их можно стыковать друг с другом для получения матрицы любого размера. Вот пример организации матрицы 7×10 точек:

[Применение силовых ключей на транзисторах]

Как Вы уже наверное успели заметить, в вышеупомянутых схемах подключения LED-индикатора аноды и катоды светодиодной матрицы подключены к портам микроконтроллера напрямую (в нашем примере аноды) и через токоограничительные резисторы (катоды).

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

В самом худшем случае, когда для нашего примера нужно зажечь все светодиоды в столбце, на один порт для анода приходится нагрузка из 8 параллельно включенных цепочек из светодиодов и резисторов 150 Ом.

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

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

Можно применить как биполярные, так и полевые транзисторы, но лучше всего поставить полевые транзисторы (MOSFET). Есть дешевые миниатюрные MOSFET транзисторы с P-каналом, например IRLML6401 или IRLML6402 в корпусе SOT-23.

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

Поэтому можно легко коммутировать большую токовую нагрузку без почти без потерь мощности – до 3.4A, что для нас более чем достаточно.

На рисунке вывод 1 обозначает затвор G (Gate), 2 исток S (Source), 3 сток D (Drain) транзистора. Чтобы умощнить аноды, транзистор нужно подключить по следующей простой схеме – затвор к порту микроконтроллера (например, к PORTA7), исток S к +5V, а сток D к анодам столбца матрицы.

Для подключения матрицы из нашего примера понадобится 8 транзисторов IRLML6401, затворы которых подключены к портам PA0..PA7 микроконтроллера ATmega32A, истоки к +5V питания, а стоки к соответствующим столбцам анодов матрицы. Нагрузочные резисторы, которые подключены к катодам матрицы, можно уменьшить для нашего примера до номинала 75 ом.

[Ссылки]

1. USB консоль для управления радиолюбительскими приборами.
2. Проект LED8x8 для AVR Studio.
3. Видеоролик на depositfiles и на YouTube.
4. Реле и транзисторы: как они работают в качестве электронных переключателей. 

Источник: http://microsin.net/programming/avr/led-matrix-dynamic-indication.html

Подключение Lcd к микроконтроллеру AVR. Урок AVR 4

Опубликовано 2010-03-07 09:55:14 автором Ruslan

Научившись мигать светодиодом, вам, наверное, захочется подключить к микроконтроллеру что-то более информативное, например Lcd дисплей. Как это сделать? Да всё, как всегда, очень просто. Символьный ЖКИ мы подружим сегодня с нашим старым знакомым ATmega8. Для этого нам потребуется сам Lcd, я использовал знакосинтезирующий ЖКИ 16×2, и микроконтроллер atmega8.

Для начала напишем программу, которая будет что-либо выводить на дисплей. Для этого откроем Code Vision AVR, создадим новый проект. В закладке LCD выбираем порт, к которому будет подключен дисплей.

Я подключил к порту D, выбираем File -> Creative Save and Exit. Указываем, куда будем сохранять файлы и смотрим на код программы.

Далее для вывода строки нам понадобится добавить несколько строк кода

  • char *buffer_Lcd=”Hello”; //Создаем выводимую строку
  • lcd_gotoxy(0, 0); // Переводим курсор на первый символ первой строки
  • lcd_puts(buffer_Lcd); // Выводим строку

Полный код представлен ниже:

#include
// Alphanumeric LCD Module functions
#include
char *buffer_Lcd=”Hello”; //Создаем выводимую строку void main(void)
{
// Input/Output Ports initialization
// Port B initialization
PORTB=0x00;
DDRB=0x00; // Port C initialization
PORTC=0x00;
DDRC=0x00; // Port D initialization
PORTD=0x00;
DDRD=0x00; // Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
TCCR0=0x00;
TCNT0=0x00; // Timer/Counter 1 initialization
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00; // Timer/Counter 2 initialization
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00; // External Interrupt(s) initialization
MCUCR=0x00; // Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x00; // USART initialization
// USART disabled
UCSRB=0x00; // Analog Comparator initialization
ACSR=0x80;
SFIOR=0x00; // ADC initialization
// ADC disabled
ADCSRA=0x00; // SPI initialization
// SPI disabled
SPCR=0x00; // TWI initialization
// TWI disabled
TWCR=0x00; // Alphanumeric LCD initialization
// Connections specified in the
// Project|Configure|C Compiler|Libraries|Alphanumeric LCD menu:
// RS – PORTD Bit 0
// RD – PORTD Bit 1
// EN – PORTD Bit 2
// D4 – PORTD Bit 4
// D5 – PORTD Bit 5
// D6 – PORTD Bit 6
// D7 – PORTD Bit 7
// Characters/line: 16
lcd_init(16);
lcd_gotoxy(0, 0); // Переводим курсор на первый символ первой строки lcd_puts(buffer_Lcd); // Выводим строку while (1) { }
}
}

Функция Объявлениe
lcd_init(количество_символов_в_строке) Инициализирует ЖКИ с введенным количеством символов в строке.
lcd_gotoxy(x, y) Переводит курсор в точку (x, y).
lcd_clear() Очищает ЖКИ
lcd_puts(char *stroka) Выводит массив символов
lcd_putchar(char simvol) Выводит один символ

Таблица 1. Функции библиотеки Lcd.

h для работы с дисплеем

Давайте теперь разберемся с выводами дисплея.

  • Vdd – + 5 вольт. – Питание Lcd.
  • Vss – Земля ( – ). – Питание Lcd.
  • V0 или VEE – контрастность дисплея. – Если посадить этот вывод на минус без резистора,то мы получим максимальную контрастность. Необходимо этот контакт подключить к минусу через переменный резистор примерно на 10 кОм.
  • А и К анод и катод подсветки lcd
  • RS – командный флаг – если подать 0, то мы посылаем команду. 1 – посылаются данные.
  • R/W – Чтение/запись – 1 – читаем данные, 0 – записываем.
  • E – импульс – чтобы lcd начал обработку данных с остальных выводов
  • DB0 – DB7 – служат для передачи данных между lcd и микроконтроллером

Для повторения в железе нам понадобится программатор USBasp, отладочная zif панель и lcd дисплей.

Подсоединяем дисплей как сказано выше, заливаем прошывку в мк я использовал avr dude команда для прошывки sudo avrdude -c usbasp -p m8 -U flash:w:'/media/ruslan/Media/Greenchip.com.ua/Lessons/lcd/Exe/lcd.hex':iи получаем

Проект в Proteus и программа к уроку находятся в архиве lcd.zip.

Источник: http://articles.greenchip.com.ua/1-1-27.html

Семи сегментный индикатор и AVR. Динамическая индикация. Программа на Си. Шаг №5

Обновлено 3.04.15. Всем привет. В прошлой статье мы с Вами рассмотрели алгоритм общения с ЖКИ, а также вывод информациина нее, и протестировали в симуляторе.

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

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


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

Если индикаторов несколько, следовательно и управляются катоды несколькими ножками МК. !!! Но всегда используйте транзисторы, т.к. порты ввода-вывода могут сгореть из-за относительно большого тока. Я использовал обычные 315 транзисторы.

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

для отображения информации на сегментах 8 ножек (7 +точка) и по одной ножки на каждый индикатор для его управления, у меня их три, поэтому и ножки управления тоже три. Ниже я привел и описал программу. Для управления сегментами  будем использовать пины одного порта, что б не путаться.

Писал под микроконтроллер ATmega8. Если Вы хотите отвязаться от “камня” то это не проблема, например в разбиваем код на библиотеки, где без проблем можно изменить настройки под другой “камень”, в основном это номера пинов и портов. Там же описаны общие правила универсальности и переноса.

Рисунок подключения транзистора к МК и индикатору.

Перейдем к программе. В этой небольшой программе (на Си) я привел пример включения трех элементов индикатора и вывод числа с запятой. Использование таймера и прерывания для вывода на индикатор.

В ходе написания программы мы должны определиться какой пин порта должен соответствовать сегменту на индикаторе. Сам элемент индикатора приведен на рисунке ниже. Сбоку описание подключения выводов к сегментам элемента индикатора(пин порта – номер ножки элемента (рис.

выше) – буква сегмента – число в массиве, отвечающее за включение сегментов на элементе).

PB0 — 12 — управление первым элементом

PB6 — 9 — управление вторым элементом
PB7 — 8 — управление третьим элементом
PD7 – 11 — (A) — 128
PD6 – 10 — (F) — 64
PD5 – 7 — (B) — 32
PD4 – 5 — (G) — 16
PD3 – 4 — © — 8
PD2 – 3 — (DP) — 4
PD1 – 2 — (D) — 2
PD0 – 1 — (E) — 1

 #include

 #include

 #include

 /*Определим каждому пину порта элемент семи сегментника (риунок выше)*/

 #define a 128

 #define b 32

 #define c 8

 #define d 2

 #define e 1

 #define f 64

 #define g 16

 #define dp 4

 /*Эти макросы содержат числа, соответствующие двойке, возведенной в степень, равной номеру    “ножки” того порта, к которому подключен сегмент индикатора с одноименным макросу названием.*/

 short unsigned int j, k = 0;  /*переменные исп-ся в макросе прерывания*/

 float i = 0;    /*Переменная для вывода на индикатор*/

short unsigned int w = 0; /*Переменная индикатор для включения точки*/

unsigned char Slot[11];  /*Массив в котором хранятся числа, которые нужно

вывести через порт на индикатор, чтобы он показал цифру, равную номеру

  элемента массива. Числа зависят только от макросов.*/

 void Slot_init ()  /*Функция инициализации индикатора*/

 {

         Slot[0] = (a+b+c+d+e+f);

         Slot[1] = (b+c); 

         Slot[2] = (a+b+g+e+d);

         Slot[3] = (a+b+g+c+d);

         Slot[4] = (f+g+b+c);  /*Имена макросов соответствуют именам сегментов индик*/

         Slot[5] = (a+f+g+c+d);

         Slot[6] = (a+f+g+c+d+e);

         Slot[7] = (a+b+c);

         Slot[8] = (a+b+c+d+e+f+g);

         Slot[9] = (a+b+c+d+f+g);

         Slot[10] = dp;   /*Точка*/

 }

/*В этих переменных хранятся цифры, которые нужно отобразить*/

 char Elem1, Elem2, Elem3; 

 /* Функция выделяет цифры из трехзначного числа Number*/

 void Display (float Number)

 {

        float N1, N2; /*Переменные для функции modf*/

        N1 = modf (Number, &N2); /*Разбиваем число на целую и дробную части,                                                                                                             N1  = дробной N2 = целой*/

        if (N1 != 0) /*Еслине равно нулю то присутствует дробь*/ 

       {

                  Number= Number*10; /*тогда умножаем число на 10, для обычного вывода                                                                                                  на  индикатор трехзначного дробного числа*/

                  w = 1; /* переменная индикатор которая используется в цикле ниже,                                                 чтобы  включать точку*/

        }

        short unsigned int Num1, Num2, Num3;

        Num1=Num2=0;

        while (Number >= 100) /*Сотни*/ 

       {

                Number -= 100;

                Num1++;

       }

       while (Number >= 10) /*Десятки*/ 

      {

               Number -= 10;

               Num2++;

      }

       Num3 = Number; /*Еденицы*/ 

       Elem1 = Slot[Num1];

       if (w == 1) /*Условие дя включения точки на втором элементе*/

       {

                Elem2 = (Slot[Num2]|0×04); /*логическое сложение с пином отвечающим за                                                                                                        точку*/

                w = 0;    /*Выключаем точку*/

        }

        else

                Elem2 = Slot[Num2];

        Elem3 = Slot[Num3];

       }

int main (void) /*начало основой программы*/

{

        DDRB = 0Xff;  /*все выводы порта B сконфигурировать как выходы*/

        DDRD = 0xff; /*все выводы порта D сконфигурировать как выходы*/

        PORTD = 0×00; /*Устанавливаем 0*/ 

        PORTB |= _BV (PB6);

        PORTB |= _BV (PB0);

        PORTB |= _BV (PB7);

        Slot_init (); 

        sei (); /*Разрешить общее прерыввание*/

        /*Инициализация таймера Т0*/

       TIMSK = (1

Источник: http://www.ap-impulse.ru/podklyuchaem-semisegmentnyj-indikator-i-pishem-programmu-shag-5/

Ссылка на основную публикацию
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}