Символьный жки на базе контроллера hd44780

Белоярский. Новости, комментарии. – LCD дисплей HD44780

В прошлой статье, если кто помнит, мы подключали к нашей Ардуине температурный датчик DS18B20 и измеряли температуру, причем результат измерений наблюдали пока что только в “Мониторе последовательного порта” программы Arduino IDE.

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

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

Для нас главное, чтобы они были совместимы с системой команд контроллера HD44780. А как там они будут называться – дело десятое. Вот как выглядят эти индикаторы:

Этот индикатор может отображать 2 строки по 16 символов в каждой (16/2).

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

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

В-общем, припаяю-ка я к нему шлейф, взятый из старого компьютера. С разъемом, естественно, чтобы можно было удобно подключить индикатор к нашей макетке:

Индикатор имеет 14 выводов:

  • 1 — Vss, земля ⇨ подключаем к выводу GND Ардуины.
  • 2 — Vdd, питание ⇨ подключаем к выводу +5 В.
  • 3 — Vo, управление контрастностью напряжением ⇨  подключаем к ползунку потенциометра.
  • 4 — RS, выбор регистра ⇨ подключаем к выходу 12 Arduino.
  • 5 — R/W, чтение/запись ⇨ подключаем к GND (шине “-“), будем только записывать в индикатор.
  • 6 — E, он же Enable ⇨ подключаем к выходу 11 Arduino.
  • 7-10 — DB0-DB3, младшие биты 8-битного интерфейса; не подключены.
  • 11-14 — DB4-DB7, старшие биты интерфейса ⇨ подключаем последовательно к выходам 5-2 Arduino
  • 15 — A, питание для подсветки ⇨ +5 В 
  • 16 — K, земля для подсветки ⇨ GND

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

Поэтому, для начала не будем полностью подключать индикатор к Ардуине, а соберем вот такую схему:

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

Далее я пробовал подключать сопротивление на 22 ком – особой разницы не заметил, кроме остроты настройки. Напомню, что этот резистор служит для настройки контрастности изображения. У меня, почему-то, пришлось его выкрутить доотказа в одну сторону. Соответственно, подключаем выводы 1 и 2 индикатора к шинам питания, согласно списку, который приведен выше.

Соединяем макетную плату с Ардуиной проводами питания, включаем – и вуаля:

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

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

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

Выводы подсветки у меня находятся отдельно, с правой стороны и обозначены буквами “А” – это “+”,  и “К” – это “-“. Присоединяем их прямо к шине питания.

 В Arduino IDE за работу с индикаторами типа HD44780 отвечает библиотека LiquidCrystal, на всякий случай проверим ее наличие:

Ок, библиотека присутствует. Тогда давайте загрузим а Ардуину такой скетч:

#include //подключаем библиотеку.

LiquidCrystal lcd(12, 11, 5, 4, 3, 2); // Указываем к каким пинам Ардуины подключен наш индикатор

void setup() {
 
  lcd.begin(8, 2);   // указываем тип индикатора – сколько столбцов и строк.
 
  lcd.print(“Probelum”);  // печатаем сообщение
}

void loop() {
   /* Устанавливаем курсор в 1 столбец 2й строки. Нумерация идёт с нуля,
  * первым аргументом идёт номер столбца.
  */
 lcd.setCursor(0, 1);
 /* Выводим на дисплей число секунд, прошедших с момента старта Arduino */
 lcd.print(millis() / 1000);

}

После загрузки скетча любуемся результатом:

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

 Кроме функций, которые мы использовали в скетче, существуют еще и другие:

  • home() и clear()Первый метод возвращает курсор в начало экрана; clear() делает то же самое, заодно стирая всё, что было на дисплее до этого.
  • write(ch)Выводит одиночный символ ch на дисплей.
  • Cursor() и noCursor()включит и выключить отображение курсора (символ подчеркивания).
      • blink() и noBlink()Включить и выключить мигание курсора, если включено его отображение.
      • display() и noDisplay()Включить и выключить дисплей.
      • scrollDisplayLeft() и scrollDisplayRight()Прокрутить экран на один символ влево или вправо.
      • autoscroll() и noAutoscroll()Включить и выключить режим автопрокрутки. В этом режиме при выводе каждого следующего символа содержимое экрана будет смещено на один символ влево (или вправо, если включен режим вывода справа налево), а выводимый символ займёт место первого сдвинутого. Проще говоря, в этом режиме все последующие символы выводятся в одно и то же место, вытесняя текущее содержимое экрана.
      • leftToRight() и rightToLeft()Устанавливают направление вывода текста: слева направо и справа налево, соответственно.
      • createChar(ch, bitmap)Самая крутая функция: позволяет создать свой символ с кодом ch (от 0 до 7), пользуясь массивом битовых масок bitmap для задания тёмных и светлых точек.

    Однако, изучение всех функций управления индикатором оставим любителям самостоятельных исследований – информации в сети полно, а сами опять сосредоточимся на нашем термометре. Снова подключим наш термодатчик DS18B20, который мы подключали в прошлой статье.  Откроем скетч, который мы тогда использовали для измерения температуры и попробуем вывести температуру на наш индикатор:

  • #include          //подключаем библиотеку “1-Wire”
    #include //подключаем библиотеку LiquidCrystal.

    OneWire  ds(10);                  // Указываем, к какому пину Ардуины подключен датчик DS18B20
    LiquidCrystal lcd(12, 11, 5, 4, 3, 2); // Указываем к каким пинам Ардуины подключен наш индикатор

    void setup(void) {
      lcd.begin(8, 2);   // указываем тип индикатора – сколько столбцов и строк.

    }

    void loop() {
      byte data[2];           // объявляем массив из 2-х байт
      String znak;            // переменная, знак температуры.
      ds.reset();             // инициализируем датчик
      ds.write(0xCC);         // пропускаем адресацию к конкретному датчику (у нас он один)
      ds.

    write(0x44);         // даем команду измерять температуру
      delay(1000);           // ждем 1 секунду, пока измеряется температура
     
      ds.reset();            // снова инициализируем датчик
      ds.write(0xCC);        // снова пропускаем адресацию
      ds.write(0xBE);         // даем команду готовности считывать температуру
      data[0] = ds.

    read();    //считываем  младший
      data[1] = ds.read();    // и старщий байты
      if bitRead(data[1],7)   // если старший бит старшего байта – 1, это отрицательная темпер.
         {znak = “”;}
         else
         {znak = “+”;}
      int Temp = (data[1] > 4;                     // к нужному виду.
     
    lcd.

    clear();                            //очищаем экран индикатора
    lcd.print(“Temper:”);                   // печатаем сообщение

     /* Устанавливаем курсор во 2й столбец 2й строки. Нумерация идёт с нуля,
      * первым аргументом идёт номер столбца.
      */
     lcd.

    setCursor(2, 1);

          if (Temp < 0)            // если температура отрицательная, то выводим только ее.
             lcd.print(Temp);
             else
             lcd.

    print(znak + Temp); // если положительная –  дополнительно выводим знак “+”.
     
    }

  • Все, что красным шрифтом, относится к обслуживанию индикатора. Вывод в последовательный порт убран, сейчас он уже не нужен. Думаю, что из комментариев работа программы ясна. Единственное, что хочется пояснить – как мы помним, на “Монитор последовательного порта” положительная температура выводилась без знака, а отрицательная уже со знаком “-“. Поэтому, нам необходимо организовать дополнительно индикацию знака “+” на положительных температурах. Что мы и проделали с помощью вот этого кусочка кода:
  •     if (Temp < 0)            // если температура отрицательная, то выводим только ее.
             lcd.print(Temp)
  •          else
  •          lcd.print(znak + Temp); // если положительная – дополнительно выводим знак “+”.
  • Загружаем скетч и получаем результат:
    • Как видим – наш термометр работает, показывает правильную температуру, в том числе – и отрицательную, проверено. Желающие, используя другие возможности такого индикатора, могут поэкспериментировать с другими функциями по выводу текста. 
    • Еще пару слов по поводу поддержки русского языка. Наши китайские товарищи, как пишут коллеги, достаточно легкомысленно отнеслись к этому вопросу, разбросав русские буквы по таблице знакогенератора в полном беспорядке. Поэтому, вот так просто вывести текст на русском языке, как мы выводим по-английски – скорее всего, не получится, желающие могут поэкспериментировать, сам не пробовал. 
    • Вот ссылка на библиотеку LiquidCrystalRus, якобы она позволяет воспроизводить русские буквы на нашем индикаторе. По отзывам – у одних получается, у других – нет, поэтому, однозначно рекомендовать не могу. Пробуйте. Сначала устанавливается библиотека стандартным способом, потом – подключается к скетчу тоже, как обычно, через #include. Команды те же самые, только вместо английских букв выводишь русские, типа – “Здравствуй , мир!”.

Источник: http://probelum.ru/index.php/izmeryaem-temperaturu/lcd-displej-hd44780

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

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

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

Но есть тут одна особенность — DDRAM память гораздо больше чем видимая область экрана.

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

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

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

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

Поскольку знакоместо у нас 5 на 8 точек, то старшие три бита роли не играют. Всего в CGRAM может быть 8 символов, соответственно CGRAM имеет 64 байта памяти.

Эти программируемые символы имеют коды от 0х00 до 0х07..

Доступ к памяти.

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

Видимая и скрытая область экранной памяти

Структура адресации контроллера HD44780

Формирование символа в ячейке CGRAM

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

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

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

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

Параметры команд имеют следующие значения

§ I/D — инкремент или декремент счетчика адреса. По дефолту стоит 0 — Декремент. Т.е. каждый следующий байт будет записан в n-1 ячейку. Если поставить 1 — будет Инкремент.

§ S– сдвиг экрана, если поставить 1 то с каждым новым символом будет сдвигаться окно экрана, пока не достигнет конца DDRAM.

§ 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

Ниже показано подключениене ЖКИ к МК

Алгоритм

Дата добавления: 2016-12-27; просмотров: 1707;

Источник: https://poznayka.org/s78926t1.html

Работа с LCD дисплеем на HD44780 AVR

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

Datasheet

Заказал с ebay дисплей 2 линии на 16 символов каждая.
Вообщем HD44780 это контроллер управления одноцветным LCD дисплеем, такие дисплеи были очень популярны в 90-е   [ wiki ] связку контроллер, дисплей и внешние выводы я буду называть просто дисплей. У таких дисплеев 16 выводов

1) VSS –  GND, земля или общий провод.

2) VDD – питание контроллера 2.7 – 5.5 В
3) V0 – настройка контрастности, нужно подбирать вручную, у меня всё ясно видно при 2,16 В если использовать 1 линию, 1,19 В если 2. В моём случае яркость отображения символов, меняется в зависимости от количества используемых линий.
4) RS – выбираем что записывать (читать)  0 – команды, 1 – символы.
5) RW – 0 – записывать, 1 – считывать, обычно этот вывод заземляют если предполагается что нужно будет только записывать символы.
6) E – подав сюда импульс происходит передача команды дисплею.
7 – 10) D0 – D3 – low биты передачи данных, не используются при 4 битной работе.
11 – 14) D4 – D7 – high биты передачи данных
15) A – Анод подсветки дисплея (+), советуют ставить 100 ом резистор, но у меня и без него всё в порядке.
16) K – катод подсветки.

Для того чтобы общаться с дисплеем необходимо ему говорить что происходит передача данных, для этого подается импульс на вывод E не меньше 230 нс.

Для того чтобы узнать что команда выполнена можно либо подождать некоторое время, (для каждой команды указано сколько необходимо ждать). Либо проверять “busy flag”.

Когда происходит выполнение команды дисплей выставляет “busy flag”, когда команда выполнилась он его сбрасывает.

Его можно считать  подав на RS 0, RW 1, и тогда он будет на выводе D7, но всё равно следует подождать некоторое время даже если он равен 0, не меньше 6 мкс.

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

Чтобы вывести определённый символ нужно передать его код дисплею при RS 1, RW 0,

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

Команды для работы с дисплеем.

 
1) Clear display – очистить дисплей и вернуть курсор в левый верхний угол (начало).
2) Return home – вернуть курсор в начало.
3) Entry mode set – выбор как будут выводиться символы на экране при их записи. I/D = 1 курсор движется вправо, 0 влево. S = 1 – вместо курсора движется дисплей, 0 – нет.

I/D =0S = 0
I/D =0S = 1
I/D =1S = 0
I/D =1S = 1

4) Display on/off control  – D дисплей вкл (1) / выкл (0), C курсор вкл (1) / выкл (0), B курсор мигает (1) / нет (0).

5) Cursor or display shift – сдвигает S/C 0 = курсор, S/C 1 = дисплей, влево R/L = 0 или вправо R/L = 1/

6) Function set – настраиваем режим работы дисплея, DL = 1 8 бит ( 0 = 4 бита ), N = 1  2  линии ( 0 = 1 линия ), F = 1 шрифт 5×10, = 0 5×8

7) Set CGRAM adress – используется для записи своих символов

8) Set DDRAM adress – используется для перемещения курсора.

9) Read busy flag and adress – чтение “busy” флага/

Рассмотрим работу с дисплеем на примере, используется ATmega8, дисплей 2×16 и передавать данные буду по 8 битам.

Сразу обозначаю ножки которые буду использовать, работаю с ATmega8 у которой нет 8 выводов на 1 порт, поэтому использую несколько портов.

//PORT B
#define PIN_RS 0
#define PIN_RW 1
#define PIN_E 2 //PORT C
#define PIN_DB0 0
#define PIN_DB1 1
#define PIN_DB2 2
#define PIN_DB3 3 //PORT D
#define PIN_DB4 0
#define PIN_DB5 1
#define PIN_DB6 2
#define PIN_DB7 3
Здесь я проверяю “busy” флаг, чтобы узнать что команда выполнена, для передачи нужно подать импульс который измеряется в нс, так что 1 мкс должно хватить.void wait_busy()
{ PORTB |= ( 1

Источник: http://4a4ik.blogspot.com/2014/07/lcd-hd44780.html

PIC и ЖКИ на HD44780, часть 1

18.05.2015 | Рубрика: PIC – микроконтроллеры

В прошлых статьях я выводил информацию на восемь светодиодов. Это ни фига не информативно и не интересно — надоедает буквально за первые пять минут. Значит пришла пора разобраться с такой классикой жанра как ЖКИ (LCD).

Под катом часть первая. Вводная.

Контроллер HD44780 — документация

ЖКИ — Жидкокристаллический индикатор, иногда говорят жидкокристаллический дисплей, дисплейчик. На английском LCD — liquid crystal display.

Индикатор, с которым я буду устраивать эксперименты был куплен на ebay. На дисплее была надпись QC1602A v2.0. По этому названию нашлась документация (datasheet):

LCD-QC1602A-datasheet LCD-QC1602A-datasheet.pdf

Языки: English
Категория: Datasheets
Лицензия: Freeware
Дата: 14.05.2015

Сразу скажу, дока совершенно негодная для радиолюбителей — так, размеры конструктору посмотреть и все. В данном случае это совершенно естественно, поскольку смотреть нужно документацию не на сам дисплей, а на контроллер. Применяемый контроллер — HD44780. Вот немного документации на контроллер на английском:

Языки: English
Категория: LCD
Лицензия: Freeware
Дата: 14.05.2015

Русскоязычная документация на контроллер на всеми уважаемом портале http://www.gaw.ru/data/lcd/lcd.pdf

Кодировки

Кодировка (один из варинтов) контроллеров HD44780:

Кодировка HD44780

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

Кодировка (кириллица) HD44780

Обращаю отдельное внимание, что в кириллической части отсутствуют те символы, которые могут быть взяты из латинских. Так, например, нет букв А, а, В, М, К и т.д. Это привело к тому, что при выводе русского текста на дисплей, нет возможности использовать какую-либо кодировку. В то же время, коды латинских  символов совпадают со стандартной кодировкой windows CP1252.

hd44780 — создаем свои символы

В контроллере HD44780 имеется возможность «рисования»своих символов. Этих символов может быть восемь, располагаются в начале таблицы занимая первые восемь знакомест. Следующие восемь знакомест дублируют первые восемь. Зачем это было сделано мне не известно, если кто-то знает — напишите в коментах. Знакоместа своих символов показаны на рисунке:

HD44780 — знакоместа своих символов

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

CGRAM — свои символы в HD44780

Используя эту возможность контроллера HD44780 можно выводить текст на русском языке даже в том случае, если дисплей не русифицирован. Разумеется, одновременно можно отображать не более восьми различных символов.

И все же, крайне рекомендую, в проектах с кириллицей использовать дисплеи с соответствующей кодировкой, а свободно создаваемые символы использовать по назначению — для вывода специальных значков вроде мнемоники батарейки, антенны, значка температуры и т.п. Например progress bar:

Питание дисплея

У ЖК дисплеев этого типа необходимо два питания — основное (+5В) и дополнительное, V0 которым устанавливается контрастность дисплея. Причем V0 на самом деле считается не от GND, а от плюса основного питания. Для ЖК дисплея QC1602A v2.0 номинальное напряжение V0 примерно -3,8В относительно положительного контакта питания.

Это означает, что при питании дисплея напряжением 5В, на V0 необходимо подать 1,2В относительно GND (общий провод, земля). При питании дисплея напряжением 3,8В, на V0 необходимо подать 0В относительно GND (соединить с общим проводом).

Питание ЖКИ

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

Vо меняется вместе с питанием

Если уменьшить напряжение питания еще, то V0 потребуется делать отрицательным.

В реальности два источника питания использовать необязательно, для формирования V0 достаточно использовать делитель на подстроечном резисторе:

Формирование Vo резистором

Забегая вперед скажу, что я на отладочной плате подключил V0 к ЦАП. Это позволит регулировать контраст программно

Источник: https://pro-diod.ru/programms/pic-micro/pic-zhki-hd44780.html

AVR: подключаем lcd hd44780

Существует множество различных LCD дисплеев, но наиболее простыми в освоении являются текстовые дисплеи на основе контроллера hd44780, которые стали де-факто стандартом на  символьные ЖКИ.

Описание контроллера LCD hd44780

  • встроенный знакосинтезатор, для вывода символа достаточно записать его код в соответствующую область (DDRAM) памяти контроллера
  • параллельный интерфейс,  4 или 8 линии данных, три управляющих линии
  • возможность загружать  в память знакосинтезатора  (CGRAM)  произвольные символы

Система команд lcd контроллера hd44780

Очистить дисплей

bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
1

Переход в начало экрана

bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
1 *

Сдвиг курсора или экрана при записи символа

bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
1 I/D S

I/D – режим увеличения/уменьшения адреса DDRAM: 0 – адрес уменьшается (сдвиг влево) , 1 –  адрес увеличивается ( сдвиг вправо )
S –  сдвиг дисплея : 0 – сдвига нет, 1 – сдвиг происходит согласно параметру I/D

Вкл/выкл дисплей, курсор, мигание

bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
1 D C B

D – Вкл/выкл  дисплея:  0 – дисплей выключен, 1 – дисплей включен
C – Вкл/выкл курсора: 0 – курсор выключен, 1 – курсор включен
B – Вкл/выкл мерцания: 0 – мерцающий курсор включен, 1 – мерцающий курсор выключен

Команда сдвига курсора/экрана

bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
1 S/C R/L * *

S/C —  сдвиг содержимого экрана: 0 — сдвигается курсор, 1 — сдвигается экран.
R/L  — направление сдвига: 0 — влево, 1 — вправо.

Разрядность шины данных, кол-во строк, размер шрифта

bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
1 DL N F * *

DL –  разрядность шины:  0 – 4 бита, 1 – 8 бит
N –  количество строк дисплея:  0 – одна строка, 1 – две строки
F –  шрифт: 0 –  5×8, 1 –  5×11

Установка адреса CCGRAM

bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
1 A5 A4 A3 A2 A1 A0

Установка адреса DDRAM

bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
1 A6 A5 A4 A3 A2 A1 A0

Кодовая таблица lcd контроллера hd44780

Русифицированные контроллеры hd44780 имеют следующую таблицу символов:

По таблице видно, что коды латинских  символов совпадают со стандартной кодировкой windows (CP1252), а кириллические символы есть только те, для которых нет аналогичных по начертанию латинских символов.  По этому в программе потребуется перекодировка из кодов символов windows в коды lcd контроллера hd44780.

Назначение выводов контроллера LCD hd44780

  1. Земля, общий провод, GND
  2. Напряжение питания, Vcc
  3. Регулировка контрастности, Vo (VEE )
  4. Выбор регистра RS ( A0) : 0 — команды, 1 — данные
  5. Выбор операции, R/W:  1 — чтение, 0  —  запись
  6.  Разрешение на выполнение операции, E.

      По заднему фронту  на этом выводе происходит запись или чтение

  7. Bit 0
  8. Bit 1
  9. Bit 2
  10. Bit 3
  11. Bit 4
  12. Bit 5
  13. Bit 6
  14. Bit 7
  15. Питание подсветки (+)
  16. Питание подсветки ( — )

При подключении по 4-х битной схеме  для шины данных используются выводы 11 , 12, 13,  14.

Схема подключения LCD hd44780 к avr atmega

Рассмотрим 8-битную схему подключения.

Линии данных подключены к порту D микроконтроллера avr. Управляющие сигналы подключены к порту С: RS — PC0, RW — PC1, E — PC2.

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

Подстроечный резистор нужен для регулировки контрастности.

Программа для микроконтроллера avr

Для доступа к портам avr atmega заведем макросы:

//линии данных
#define LCD_DATA PORTD
#define LCD_DATA_DDR DDRD
 
//управляющие линии
#define LCD_CTRL PORTC
#define LCD_CTRL_DDR DDRC
 
#define LCD_RS _BV( 0 ) /*0 – команды, 1 – данные*/
#define LCD_RW _BV( 1 ) /*0 – запись, 1 – чтение*/
#define LCD_E _BV( 2 )
 
#define lcd_set_e() LCD_CTRL |= LCD_E /*выставить в 1 линию E*/
#define lcd_set_rs() LCD_CTRL |= LCD_RS /*выставить в 1 линию RS*/
#define lcd_set_rw() LCD_CTRL |= LCD_RW /*выставить в 1 линию RW*/
 
#define lcd_clear_e() LCD_CTRL &= ~LCD_E /*выставить в 0 линию E*/
#define lcd_clear_rs() LCD_CTRL &= ~LCD_RS /*выставить в 0 линию RS*/
#define lcd_clear_rw() LCD_CTRL &= ~LCD_RW /*выставить в 0 линию RW*/

//линии данных #define LCD_DATA PORTD #define LCD_DATA_DDR DDRD //управляющие линии #define LCD_CTRL PORTC #define LCD_CTRL_DDR DDRC #define LCD_RS _BV( 0 ) /*0 – команды, 1 – данные*/ #define LCD_RW _BV( 1 ) /*0 – запись, 1 – чтение*/ #define LCD_E _BV( 2 ) #define lcd_set_e() LCD_CTRL |= LCD_E /*выставить в 1 линию E*/ #define lcd_set_rs() LCD_CTRL |= LCD_RS /*выставить в 1 линию RS*/ #define lcd_set_rw() LCD_CTRL |= LCD_RW /*выставить в 1 линию RW*/ #define lcd_clear_e() LCD_CTRL &= ~LCD_E /*выставить в 0 линию E*/ #define lcd_clear_rs() LCD_CTRL &= ~LCD_RS /*выставить в 0 линию RS*/ #define lcd_clear_rw() LCD_CTRL &= ~LCD_RW /*выставить в 0 линию RW*/

Функция генерирующая строб на линии E. По этому стробу производится запись команды/данных   или чтение.

static void lcd_pulse_e(void)
{ lcd_set_e(); _delay_us(1); lcd_clear_e(); _delay_us(1);
}

static void lcd_pulse_e(void) { lcd_set_e(); _delay_us(1); lcd_clear_e(); _delay_us(1); }

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

static void lcd_wait(void)
{ _delay_us( 40 );
}

static void lcd_wait(void) { _delay_us( 40 ); }

Функция записи байта в lcd контроллер. Команда это или данные, определяется уровнем, который был выставлен на линии RS перед вызовом данной функции.

static void lcd_write(unsigned char data)
{ LCD_DATA = data; lcd_pulse_e(); lcd_wait();
}

static void lcd_write(unsigned char data) { LCD_DATA = data; lcd_pulse_e(); lcd_wait(); }

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

#define LCD_CLR _BV( 0 ) /*Очистить дисплей*/
 
#define LCD_HOME _BV( 1 ) /*Переход в начало экрана*/
 
#define LCD_MODE _BV( 2 ) /*Сдвиг курсора или экрана при записи символа*/
#define LCD_MODE_INC _BV( 1 )
#define LCD_MODE_SHIFT _BV( 0 )
 
#define LCD_ON _BV( 3 ) /*Вкл/выкл дисплей, курсор, мигание*/
#define LCD_ON_DISPLAY _BV( 2 )
#define LCD_ON_CURSOR _BV( 1 )
#define LCD_ON_BLINK _BV( 0 )
 
#define LCD_SHIFT _BV( 4 ) /*Команда сдвига курсора/экрана*/
#define LCD_SHIFT_DISPLAY _BV( 3 )
#define LCD_SHIFT_RIGHT _BV( 2 )
 
#define LCD_FUNCTION _BV( 5 ) /*Разрядность шины данных, кол-во строк, размер шрифта*/
#define LCD_FUNCTION_8BIT _BV( 4 )
#define LCD_FUNCTION_2LINES _BV( 3 )
#define LCD_FUNCTION_10DOTS _BV( 2 )
 
#define LCD_SET_CGRAM_ADDR _BV( 6 ) /*Установка адреса CGRAM*/
 
#define LCD_SET_DDRAM_ADDR _BV( 7 ) /*Установка адреса DDRAM*/

#define LCD_CLR _BV( 0 ) /*Очистить дисплей*/ #define LCD_HOME _BV( 1 ) /*Переход в начало экрана*/ #define LCD_MODE _BV( 2 ) /*Сдвиг курсора или экрана при записи символа*/ #define LCD_MODE_INC _BV( 1 ) #define LCD_MODE_SHIFT _BV( 0 ) #define LCD_ON _BV( 3 ) /*Вкл/выкл дисплей, курсор, мигание*/ #define LCD_ON_DISPLAY _BV( 2 ) #define LCD_ON_CURSOR _BV( 1 ) #define LCD_ON_BLINK _BV( 0 ) #define LCD_SHIFT _BV( 4 ) /*Команда сдвига курсора/экрана*/ #define LCD_SHIFT_DISPLAY _BV( 3 ) #define LCD_SHIFT_RIGHT _BV( 2 ) #define LCD_FUNCTION _BV( 5 ) /*Разрядность шины данных, кол-во строк, размер шрифта*/ #define LCD_FUNCTION_8BIT _BV( 4 ) #define LCD_FUNCTION_2LINES _BV( 3 ) #define LCD_FUNCTION_10DOTS _BV( 2 ) #define LCD_SET_CGRAM_ADDR _BV( 6 ) /*Установка адреса CGRAM*/ #define LCD_SET_DDRAM_ADDR _BV( 7 ) /*Установка адреса DDRAM*/

Функция инициализации lcd контроллера hd44780.

void lcd_init( void )
{ //настраиваем на выход порт данных и управляющие пины LCD_DATA_DDR = 0xFF; LCD_CTRL_DDR |= ( LCD_E | LCD_RW | LCD_RS );
  lcd_clear_rw(); //переключаемся в режим записи lcd_clear_rs(); //записывать будем команды
  _delay_ms(15); //выбираем 8-ми битную шину и 2х строчный режим lcd_write( LCD_FUNCTION | LCD_FUNCTION_8BIT | LCD_FUNCTION_2LINES ); _delay_ms(5); lcd_write( LCD_FUNCTION | LCD_FUNCTION_8BIT | LCD_FUNCTION_2LINES ); _delay_us( 100 ); lcd_write( LCD_FUNCTION | LCD_FUNCTION_8BIT | LCD_FUNCTION_2LINES );
  //разрешаем автоматическое увеличение текущей позиции lcd_write( LCD_MODE | LCD_MODE_INC );   //включаем дисплей lcd_write( LCD_ON | LCD_ON_DISPLAY );   //установка начального адреса lcd_write( LCD_SET_DDRAM_ADDR | 0x00 );   lcd_set_rs(); //теперь будем записывать данные, выводимые на ЖКИ
}

void lcd_init( void ) { //настраиваем на выход порт данных и управляющие пины LCD_DATA_DDR = 0xFF; LCD_CTRL_DDR |= ( LCD_E | LCD_RW | LCD_RS ); lcd_clear_rw(); //переключаемся в режим записи lcd_clear_rs(); //записывать будем команды _delay_ms(15); //выбираем 8-ми битную шину и 2х строчный режим lcd_write( LCD_FUNCTION | LCD_FUNCTION_8BIT | LCD_FUNCTION_2LINES ); _delay_ms(5); lcd_write( LCD_FUNCTION | LCD_FUNCTION_8BIT | LCD_FUNCTION_2LINES ); _delay_us( 100 ); lcd_write( LCD_FUNCTION | LCD_FUNCTION_8BIT | LCD_FUNCTION_2LINES ); //разрешаем автоматическое увеличение текущей позиции lcd_write( LCD_MODE | LCD_MODE_INC ); //включаем дисплей lcd_write( LCD_ON | LCD_ON_DISPLAY ); //установка начального адреса lcd_write( LCD_SET_DDRAM_ADDR | 0x00 ); lcd_set_rs(); //теперь будем записывать данные, выводимые на ЖКИ }

Функция вывода символа, символ должен быть в кодировке win1251, для конвертирования в коды lcd контроллера  hd44780 используется таблица lcd_codepage.

void lcd_putc(unsigned char c) { if ( c == 0xA8) { //буква 'Ё' c = 0xA2; } else if ( c ==0xB8) { //буква 'ё' c = 0xB5; } else if ( c >= 0xC0 ) { c = lcd_codepage[ c – 0xC0 ]; } lcd_write( c );
}
 
unsigned char lcd_codepage[]=
{ 0x41,0xa0,0x42,0xa1,0xe0,0x45,0xa3,0xa4, 0xa5,0xa6,0x4b,0xa7,0x4d,0x48,0x4f,0xa8, 0x50,0x43,0x54,0xa9,0xaa,0x58,0xe1,0xab, 0xac,0xe2,0xad,0xae,0x62,0xaf,0xb0,0xb1, 0x61,0xb2,0xb3,0xb4,0xe3,0x65,0xb6,0xb7, 0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0x6f,0xbe, 0x70,0x63,0xbf,0x79,0xe4,0x78,0xe5,0xc0, 0xc1,0xe6,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,
};

void lcd_putc(unsigned char c) { if ( c == 0xA8) { //буква 'Ё' c = 0xA2; } else if ( c ==0xB8) { //буква 'ё' c = 0xB5; } else if ( c >= 0xC0 ) { c = lcd_codepage[ c – 0xC0 ]; } lcd_write( c ); } unsigned char lcd_codepage[]= { 0x41,0xa0,0x42,0xa1,0xe0,0x45,0xa3,0xa4, 0xa5,0xa6,0x4b,0xa7,0x4d,0x48,0x4f,0xa8, 0x50,0x43,0x54,0xa9,0xaa,0x58,0xe1,0xab, 0xac,0xe2,0xad,0xae,0x62,0xaf,0xb0,0xb1, 0x61,0xb2,0xb3,0xb4,0xe3,0x65,0xb6,0xb7, 0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0x6f,0xbe, 0x70,0x63,0xbf,0x79,0xe4,0x78,0xe5,0xc0, 0xc1,0xe6,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7, };

Функция вывода строки.

void lcd_puts( const char *str)
{ while( *str ) { lcd_putc( *str++ ); }
}

void lcd_puts( const char *str) { while( *str ) { lcd_putc( *str++ ); } }

Функция изменения текущей позиции курсора, x — номер символа в строке, y — номер строки

void lcd_goto( unsigned char x, unsigned char y )
{ unsigned char address = x; if ( y ) { address += 0x40; } lcd_clear_rs(); lcd_write( LCD_SET_DDRAM_ADDR | address ); lcd_set_rs(); }

void lcd_goto( unsigned char x, unsigned char y ) { unsigned char address = x; if ( y ) { address += 0x40; } lcd_clear_rs(); lcd_write( LCD_SET_DDRAM_ADDR | address ); lcd_set_rs(); }

Функция main

int main( void )
{ lcd_init(); lcd_goto(0,0); lcd_puts(“mainloop.ru/avr-” ); lcd_goto(0,1); lcd_puts(“atmega/lcd.html” ); for(;;) { } return 0;
}

int main( void ) { lcd_init(); lcd_goto(0,0); lcd_puts(“mainloop.ru/avr-” ); lcd_goto(0,1); lcd_puts(“atmega/lcd.html” ); for(;;) { } return 0; }

Скачать исходники примера для avr-gcc (WinAvr) можно тут.

Источник: http://mainloop.ru/avr-atmega/lcd.html

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

EasySTM32 – Библиотека для работы с HD44780

В прошлой статье мы рассмотрели теоретические основы управления LCD дисплеем на базе контроллера HD44780. Но разумеется теория без практики ничего не значит, а поэтому я предлагаю побаловаться с этим дисплеем вживую. Дисплей стоит не дорого, что-то в районе 6$, лично я экспериментировал с дисплеем под названием ACM1602K-FL-YTH-02. Редкостный отстой скажу я вам, не покупайте такой.

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

Лучше купить на бакс подороже и не иметь проблем в будующем, мне например понравились наши отечественные МЭЛТовские дисплеи они кстати лишены некоторых проблем с русскими символами (об этом подробнее позже).

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

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

Первым делом нужно скопировать папку hd44780_driver вместе со всем её содержимым в директорию с файлами своего проекта. Файлов там всего два: Один заголовочный, с кучей малопонятных дефайнов, а другой непосредственно с кодом который реализует функционал.

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

Если же вы ради удобства разводки платы или по каким либо другим причинам решили пересадить дисплей на другие выводы то нужно их указать в заголовочном файле. Первым делом указываем порт. У меня указан порт С.

После порта идет описание того к каким ножкам порта С подключены определённые ноги дисплея. Напомню, что вывод дисплея R/W я всегда жестко сажаю на землю, так как ничего из дисплея я не читаю, а только пишу в него. 

#define LCD_PORT GPIOC
#define LCD_CD 0
#define LCD_EN 1
#define LCD_DB4 2
#define LCD_DB5 3
#define LCD_DB6 4
#define LCD_DB7 5

На этом настройка заканчивается и теперь можно использовать функции библиотеки предварительно конечно же добавив в файл main.c строчку 

#include “hd44780_driverhd44780_driver.h”

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

Именно для этого служат все эти адские конструкции из директив препроцессора в заголовочном файле. После настройки ног выполняется непосредственно сама инициализация.

По умолчанию дисплей настраивается следующим образом: 4-х битный режим, включен курсор, при поступлении данных счетчик адреса увеличивается на единицу, дисплей чист, курсор в позиции X0, Y0. Для очистки дисплея используется функция lcd_clear(), с ней я думаю всё понятно.

После её вызова очищается DDRAM и курсор встаёт в позицию с координатами 0,0. Если же вам требуется просто переместить  курсор без очистки дисплея, то на этот случай в библиотеке имеется своя функция lcd_set_xy(x,y), где x и y координаты курсора на экране.

Так же присутствует функция lcd_set_state для управления отображением курсора и состоянием самого дисплея. При помощи неё можно прятать и показывать курсор и заставлять его мигать. Так же существует возможность выключать/включать LCD дисплей. Возможен вызов данной функции со следующими параметрами: 

  • lcd_set_state(LCD_DISABLE, CURSOR_DISABLE, NO_BLINK); – дисплей ничего не показывает, даже если данные в DDRAM есть. Если в качестве первого параметра выступает LCD_DISABLE, то по идее вторые два вообще не важны, так как ни какого курсора при выключенном дисплее мы не увидим.
  • lcd_set_state(LCD_ENABLE, CURSOR_DISABLE, NO_BLINK); – дисплей включен, курсора нет, ничего не мигает
  • lcd_set_state(LCD_ENABLE, CURSOR_DISABLE, BLINK); – дисплей включен, курсора нет, но мигает все знакоместо (черным квадратом)
  • lcd_set_state(LCD_ENABLE, CURSOR_ENABLE, NO_BLINK); – дисплей включен, есть не мигающий курсор
  • lcd_set_state(LCD_ENABLE, CURSOR_ENABLE, BLINK); – дисплей включен, курсор есть, мигает всё знакоместо. 

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

Следующая функция lcd_send принимает два параметра: Первый – байт данных, второй – COMMAND или DATA.  Не трудно догадаться, что она служит для передачи в дисплей байта данных или команды.

И наконец функция lcd_set_user_char предназначена для того чтоб записать пользовательский символ в CGRAM память дисплея. Подробнее о том как это сделать, будет написано в примере. 

Для того чтоб показать как оно работает я написал простенький пример который использует функции из этой библиотеки. Собственно вот он: 

#include “stm32F10x.h”
#include “hd44780_driverhd44780_driver.h”
#include “stm32f10x_rcc.h” int main(void)
{ uint8_t user_char[8]; //Сюда будем записывать пользовательский символ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); //Вкл порт С lcd_init(); //Инициализируем дисплей user_char[0]=0b01110; //А вот тут user_char[1]=0b10001; // рисуем user_char[2]=0b10001; // наш символ user_char[3]=0b10001; // user_char[4]=0b10001; // Это типа рыба 🙂 user_char[5]=0b01010; user_char[6]=0b10001; user_char[7]=0b10001; lcd_set_user_char(0, user_char); // Наша рыба это символ номер ноль lcd_out(“This is fish”); //Выводим надпись в нулевую строку lcd_set_xy(0,1); //переводим курсор в первую строку lcd_send(0,DATA); //Выводим символ номер ноль lcd_set_state(LCD_ENABLE, CURSOR_ENABLE, BLINK); //Включаем курсор и мигалку while(1) { }
}

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

Библиотека так себе, написал её буквально за полтора вечера, особо ничего не оптимизировал, поэтому прошу не пинать меня ногами если вы увидите в ней что-то вырвиглазное 🙂 Несмотря на это она таки работает! Хочу отметить два важных момента: Во-первых – чтоб работал русский язык нужно перекодировать русскую фразу. Т.е. написать lcd_out(“Привет мир”); не получится, вместо русских букв там будут каракули,не не совпадает кодировка. Кстати МЭЛТовские дисплеи имеют команду для смены кодировки, и тогда можно отправлять в дисплей русские буквы так как они есть без перекодирования. В интернетах имеются спец программы позволяющее это сделать, просто надо немного погуглить. Кстати можно просто допилить функцию lcd_out чтоб она сама выполняла перекодировку русских символов. Возможно я улучшу её позже, сейчас в этом нет необходимости. Во-вторых в библиотеке есть функция предназначенная для создания небольшой задержки. Если ваш контроллер работате на каких-то запредельных частотах – просто увеличте значение tmpvar раза в полтора. Если у вас не работает конечно. Сделать это можно в файле hd44780_driver.c строка номер 5. Ну и собственно прикладываю архив со своим проектом в кокосе. 

Источник: http://easystm32.ru/indication/24-library-for-hd44780

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