Подключение графического дисплея МТ12232-А к микроконтроллеру AVR

27/08/2011 - 08:08

Введение

   Даже монохромные графические дисплеи, не говоря уже о цветных, обладают на порядок большими возможностями по выводу информации, по сравнению со  знакосинтезирующими. Графические дисплеи позволяют выводить изображения и текстовую информацию, используя произвольный шрифт. Кроме того изображение можно выводить в любой точке дисплея, а не только в отведенных знакоместах. 
   За преимущества графических дисплеев приходиться платить деньгами и ресурсами микроконтроллера. Как правило графические дисплеи дороже знакосинтезирующих и у них нет знакогенератора и встроенных функций рисования. Поэтому вся работу по выводу текста и рисованию графики приходится выполнять микроконтроллеру. 
   В этой статье мы рассмотрим подключение и работу с графическим дисплеем МТ12232-А. Он выпускается отечественной фирмой МЭЛТ, прост в управлении и является одним из самых доступных по цене. 

Схема

   МТ12232-А - это монохромный жидкокристаллический модуль, позволяющий отображать графическое поле 122 х 32 пикселя. Размер одного пикселя 0.44 х 0.44 мм. Напряжение питания 3.3 - 5 Вольт. Потребляемый ток порядка 1.5 мА. Напряжение питания подсветки 4 В при токе в 70 мА. Габаритные размеры дисплея 77 х 38 мм.
   МТ12232-А имеет 8-ми разрядную шину данных, 5 управляющих выводов, выводы питания модуля и выводы питания подсветки. 
   Для подключения МТ12232 к микроконтроллеру понадобится 14 выводов. Теоретически, можно сэкономить 2 вывода, если не использовать вывод сброса дисплея - RESET и не управлять подсветкой. К RESET можно подключить цепочку сброса из резистора и конденсатора, однако на сайте МЭЛТ в рекомендациях по применению жк дисплеев рекомендуется подключать RESET к контроллеру.
   Подключается все довольно банально - напрямую к микроконтроллеру.
 
 Подключение МТ12232-А к микроконтроллеру AVR
 
   Материал по МТ12232 я планировал написать давно, но, как это часто бывает, постоянно не доходили руки. И вот, сев на днях за статью, я обнаружил, что в даташите на дисплей произошли изменения - 13 вывод МТ12232, который раннее не использовался и был помечен в документации как NC, теперь регулирует контрастность. Правда, при 5-ти вольтовом питании дисплея, этот резистор не требуется, поэтому мне не пришлось вносить в схему никаких изменений.

Распределение ОЗУ

   Модуль МТ12232-А имеет в своем составе два независимых контроллера, каждый из которых управляет своей половинкой жидко-кристаллического дисплея. Выбор контроллера осуществляется с помощью сигнала chip select - CS (1 -  контроллер левой половины, 0 - контроллер правой половины). 
   Изображение на дисплее представляет собой содержимое оперативной памяти этих контроллеров. Каждому черному пикселю на дисплее соответствует логическая "1" в ячейке ОЗУ. ОЗУ имеют размер 88 х 32 и разбиты на 4 страницы размером 80 х 8 бит каждая. Запись/чтение данных в/из ОЗУ осуществляется побайтно, поэтому для вывода одного пикселя приходится считывать байт ОЗУ, устанавливать нужный бит и записывать байт обратно. 
   На дисплее отображается только 61 байт из 80 для каждой страницы ОЗУ, что довольно странно. Кроме того, соответствие адресов ячеек ОЗУ и точек дисплея, которое ты можешь посмотреть в даташите, несколько неудобно. Возможно это связанно с какими-то схемотехническими или технологическими сложностями при производстве дисплеев, я не знаю. Впрочем неудобства с адресным пространством решаются посредством кода. 

Программа

   Для МТ12232-А я написал драйвер. Он реализует низкоуровневые функции обмена данными между микроконтроллером и дисплеем, функции инициализации, функции вывода текста и простой графики, как то рисование линий, окружностей и прямоугольников. 
   В конце статьи присоединены архивы проектов для компиляторов IAR, GCC и CodeVision, оттуда можно взять драйвер. Это два файла - lcd_graph_lib.c и  lcd_graph_lib.h
 
    Чтобы подключить драйвер к своему проекту нужно:
 
- скопировать хедер и сишный файл в папку проекта,
 
- включить хедер файл в main.c
       #include "lcd_graph_lib.h"
 
- настроить заголовочный файл
     задать частоту тактирования мк, порты и выводы, к которым подключен дисплей

    Низкоуровневые функции

  Черновую работу по обмену данными между микроконтроллером и дисплеем реализуют четыре функции:
 
void LCDG_SendCom(unsigned char data)   //функция записи команд
void LCDG_SendData(unsigned char data)  //функция записи данных
unsigned char LCDG_ReadData(void)         //функция чтения данных
void LCDG_WaitFLAG_BUSY(void)             //функция ожидания флага занятости  
 
   Последняя функция используется исключительно внутри драйвера.
 
   При любом обмене с модулем  МТ12232-А микроконтроллер должен выбирать один из двух контроллеров. Для этого используются макросы:
 
#define SelectLeftChip()   SetBit(PORT_LCD_CON, CS)
#define SelectRightChip()   ClearBit(PORT_LCD_CON, CS)
 
   Запись/чтение данных в контроллер модуля MT12232-A требует предварительной установки страницы ОЗУ и адреса внутри нее. Делается это с помощью команд Set Page и Set Adress, формат которых ты можешь посмотреть в документации. 
   Процедуру чтения данных нужно выполнять дважды. Первое чтение - холостое, второе - рабочее. Этот момент описан в рекомендациях на сайте МЭЛТ.
 
"При чтении информации из внутренней памяти индикатора нужно делать "пустой" цикл чтения - после команд установки адреса столбца первый цикл чтения не выдаст полезной информации, реальные данные будут выданы только начиная со второго цикла чтения. Для чтения байта статуса лишних циклов чтения делать не надо."
 
Примеры:
 
//подача команды
SelectLeftChip();
LCDG_SendCom(COM_CLEAR_RMW);
 
//запись данных
SelectLeftChip();
LCDG_SendCom(page);
LCDG_SendCom(adress);
LCDG_SendData(0);
 
//чтение данных
SelectLeftChip();
LCDG_WaitFLAG_BUSY();
LCDG_SendCom(realPage);
LCDG_SendCom(realAdr);
LCDG_ReadData();
currentData = LCDG_ReadData(); 

Функции инициализации

   Их две - инициализация портов микроконтроллера и инициализация двух контроллеров  модуля MT12232-A. Инициализация модуля представляет собой подачу последовательности команд, которая описана в документации. 
 
void LCDG_InitPort(void);     //инициализация портов                           
void LCDG_InitLcd(void);      //инициализация модуля
 
   Также к инициализации я отношу функции очистки дисплея.

void LCDG_ClrDisp(unsigned char x1, unsigned char x2);   //очищает дисплей от x1 до x2
#define LCDG_ClrAllDisp() LCDG_ClrDisp(0, 122)            //полная очистка дисплея
 
x1 и x2 - координаты по оси х, которые могут принимать значения от 0 до 122

Знакогенератор

   Знакогенератор представляет собой набор функций, реализующих вывод текста на дисплей МТ12232-А. 
   Текст можно выводить в фиксированные знакоместа и строки. Знакомест 20 штук, они задаются с помощью массива PlaceArray[] (смотри сишный файл). Количество строк соответствует количеству страниц ОЗУ, то есть их 4. Почему я не стал делать вывод текста в произвольном месте? Потому что такая реализация была бы более тяжеловесной в плане объема и скорости выполнения кода.  
   Для вывода текста используется шрифт, сохраняемых во флеш памяти микроконтроллера AVR. Шрифт описан в файле font_6x8.h. Он занимет довольно много места, из-за чего я не стал делать поддержку нескольких шрифтов.  Это будет  реализовано в следующих статьях по графическим дисплеям. 
  Текст можно выводить побуквенно, или передавая функциям указатель на строку. Также можно инвертировать цвет фона. Что может быть использовано для выделения слов, например в пуктах меню. 
 
//функции знакогенератора
//устанавливает флаг инверсии - текст будет белым, а фон темным 
void LCDG_SetInv(unsigned char flag);     
     
//выводит один символ в знакоместо                   
void  LCDG_SendSymbol(unsigned char xPos, unsigned char yPos, unsigned char data);   
 
//выводит строку из ОЗУ
void LCDG_SendString(unsigned char xPos, unsigned char yPos, char * string);    
 
//выводит строку из флэш     
void LCDG_SendStringFl(unsigned char xPos, unsigned char yPos, char __flash* string);    
   
где xPos и yPos - координаты знакоместа, которые могут принимать значения 0-19 и 0-3 соответственно
 
Примеры:
 
//устанавливаем белый фон и выводим букву
LCDG_SetInv(0);
LCDG_SendSymbol(10, 0, 'a');
 
//выводим строку из ОЗУ
LCDG_SendString(0, 0, "ChipEnable.Ru");    
 
//выводим строку из флэш памяти (IAR)
__flash char text[] = "chipenable.ru";
....
LCDG_SendStringFl(0, 1, text);
 
   При выводе строки из ОЗУ требуется меньше писанины, однако ты должен понимать, компилятор все равно определяет эту строку во флэш память микроконтроллера AVR,  просто в самом начале программы она будет подгружаться в ОЗУ. 

 вывод текста на МТ12232-А

Графические функции

   Основная графическая функция - это функция вывода одного пикселя. Как я уже говорил, для вывода одного пикселя установается страница и адрес ОЗУ, считывается байт, в нем устанавливается нужный бит и модифицированный байт записывается обратно в память. 
   Вывод пикселя (и соответственно остальной графики) может производиться по одному из трех методов - AND, OR, XOR. Это позволяет, например, накладывать одно изображение на другое.
 
Если пиксел не установлен, то вывод по методу:
AND - сбрасывает его, то есть ничего не меняет
OR -  устанавливает его
XOR - инвертирует его, то есть устанавливает
 
Если пиксел установлен, то вывод по методу:
AND - сбрасывает его
OR - устанавливает его, то есть ничего не меняет
XOR -инвертирует его, то есть сбрасывает
 
   Метод вывода задается с помощью макроопределений и фунции.
 
   Функция вывода пикселя используется для рисования линии, окружности и прямоугольника. Алгоритмы рисования линии и окружности честно содраны с просторов интернета, а функция рисования прямоугольника написана на основе функции рисования линии. 
   Вывод графики может производиться в любую область экрана. Координаты x и y могут принимать значения 0 - 121 и 0 - 31 соответственно. 
 
//методы вывода на экран
#define MET_AND  0
#define MET_OR   1
#define MET_XOR  2
 
#define FILL_OFF 0  //заполнения нет
#define FILL_ON  1  //заполнение есть
 
//графические функции
//устанавливает метод вывода пикселов на экран 
void LCDG_SetMethod(unsigned char met);    
 
//отображает один пиксел на дисплее                                             
void LCDG_PutPixel(unsigned char XPos, unsigned char YPos); 
 
//рисует линию
//(x1, y1) и (x2, y2) координаты начала и конца линии
                          
void LCDG_DrawLine(unsigned char x1, unsigned char y1, unsigned char x2, unsigned char y2); 
 
//рисует окружность
 //(x,y) - координаты центра окружности 
void LCDG_DrawCircle(unsigned char x,unsigned char y,unsigned char r);   
 
//рисует прямоугольник с заполнением или без него  
//(x1, y1) и (x2, y2) координаты верхней и нижней вершины    
void LCDG_DrawRect(unsigned char x1, unsigned char y1, unsigned char x2, unsigned char y2, unsigned char fill); 

 
вывод графики на МТ12232-А
 
Надеюсь представленный материал облегчит тебе освоение графического модуля MT12232, да и других графических дисплеев.

Файлы

Comments   

# greenvovk 2011-08-29 15:40
Огромное спасибо за материал, и за сайт в целом. Сейчас ковыряюсь с одним маленьким проектом на основе событийной системы, в котором бы сам разбирался год. Но благодаря твоим материалам проект почти закончен. Обязательно как закончу, пришлю весь рабочий материал на твой суд. Укажи куда. С уважением greenvovk:)
# Pashgan 2011-08-29 19:02
Пришли на это мыло microsmaster@yandex.ru
# neiver 2011-08-31 14:01
Интересно, а зачем собственно нужен этот:
Code:unsigned char PlaceArray[] = {0,6,12,18,24,30,36,42,48,54,60,66,72,78,84,90,96,102,108,114};
Почему вместо
Code:realAdr = PlaceArray[xPos];
не написать
Code:const int char_width = 6;
...
realAdr = xPos * char_width;

???
ИМХО, будет и быстрее и компактнее.
# Pashgan 2011-08-31 16:04
Согласен
# leddel 2011-09-03 08:44
для полного счастья не хватает генерации 2KHz которых требуют доступные у нас на перефирии дисплеи WINSTAR типа WG12232E-TML, а так материальчик годный, спасибо
# Каримов 2011-12-21 12:04
А не могли бы Вы подсказать схемку для дисплея WB160128B-TFH-T #P\Winstar?
# Kodex 2013-09-29 15:14
Интересная вещь, использовать читаемые данные после второго чтения. Получается, после первого чтения счетчик не инкременируется ? В протеусе щас играюсь со старшим братом этого LCD, который 128*64. Низкоуровневые функции уже работают. Функция вывода работает (по подсчетам студии) 14 мкс без опросов флагов. Все б ничего, только в функции пара задержек на сумму 18 мкс. Оптимизация!!! Есть пара видео о выводе на данный экран avr 3D, попробую реализовать, но вряд ли осилю.
# JoJo 2013-09-29 20:25
Попробуй. Потом покажешь нам, что получилось.
# Stas 2015-01-11 17:32
Спасибо за исходник, наконец-то завелся мой WG12232E. Уже 4 года валяется не мог никак его обуздать и вдруг - О ЧУДО! - он покорился этому исходнику с минимальными правками! Недостаток - мега16 и отсутствие буфера а у меня 32я - но это уже допилю сам...
# SerF 2016-04-06 20:56
Здравствуйте.
Будет работать данный индикатор при частоте контроллера 8МГц?
# SerF 2016-04-28 21:07
Здравствуйте.
Есть у вас модель протеус для данного дисплея?

У вас недостаточно прав для комментирования.