Использование графического LCD WG12864A.

Автор - molchec.
Наряду с символьными ЖК, современные производители выпускают разнообразные графические индикаторы. Если у символьных, как правило, использован одинаковый интерфейс управления и система команд, то в графических индикаторах существует широкий ряд управляющих контроллеров со своими командами. Также следует обратить внимание на встроенный генератор отрицательного напряжения - при его отсутствии нужно будет использовать дополнительный источник питания. В данной статье мы рассмотрим ЖК дисплей WG12864A с управляющим контроллером фирмы Samsung ks0108. Непосредственно ЖК дисплеем управляет два контроллера ks0108 - каждый своей половиной дисплея 64*64 точек, выбор соответствующего чипа осуществляется выводами CS1 и CS2. При высоких уровнях на обоих выводах запись осуществляется в оба чипа.
Назначение выводов индикатора:
1.       Vss - общий 0В.
2.       Vdd - +5В питание логики.
3.       Vo - контрастность.
4.       D/I - выбор данные/инструкции 1-данные 0-инструкции.
5.       R/W - чтение/запись 1- чтение, 0-запись.
6.       E - стробирующий сигнал при записи/чтении.
7-14.  DB0-DB7 - шина данных/инструкций.
15.     CS1 - выбор кристалла.
16.     CS2 - выбор кристалла.
17.     RST - сброс.
18.     Vee - выход отрицательного напряжения.
19.     A - анод подсветки
20.     K - катод подсветки.
Управление контрастностью осуществляется отрицательным напряжением с вывода Vee.
Система команд ЖК:
Перед работой непосредственно с железякой рекомендую сначала отработать прошивку в Proteus, что я сам и сделал.
Питание, контрастность и пр. на индикатор подключать не надо - программа по умолчанию всё делает. Тип индикатора в среде выбран LGM12641BS1R - тут главное, чтоб управляющий контроллер был тот же и выводы CS не инвертирующие, есть и такие модели ЖК. Просто в поиске пишем ks0108, и прога отобразит все доступные в вашей версии ЖК. Контроллер ATMEGA8. Чтоб отключить подключаемый по умолчанию кварц выводам счётчика Т2 в поле TOCP Frequency надо стереть значение оставив поле пустым, в дальнейшем там будет отображаться (Default). Подробнее о работе в среде Proteus написано в обучалке.
Настало время приступить непосредственно к написанию прошивки. Я пишу на Си в компиляторе ICC for AVR, в функциях использованы преимущественно функции сброса/установки пинов так, что думаю адаптировать код можно под любой компилятор, при желании и под ассемблер.

Для удобства адаптации под другие порты и контроллеры я задаю регистры ввода/вывода следующим образом (согласно схеме) в файле основной программы.
#define LCD_RST 0b00000001
#define LCD_E      0b00000010
#define LCD_RW  0b00000100
#define LCD_RS   0b00001000
#define LCD_CS2 0b00010000
#define LCD_CS1 0b00100000

#define LCD_DB PORTD       //Шина данных
#define LCD_COM PORTC   //порт управляющих выводов

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

Функции работы с ЖК располагаю в файле ks0108.h, который обязательно надо включать после объявления регистров и пинов см. выше.
...
#define LCD_COM PORTC  //порт управляющих выводов
#include "ks0108.h"

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

Описание функций, находящихся в файле ks0108.h.
void WriteCom(unsigned char Com, unsigned char CS)
Запись команды: Com команда, CS выбор кристалла.

void WriteData(unsigned char data,unsigned char CS)
Запись данных: data данные,СS выбор кристалла.

Обращаю внимание на комментированные строки:
//SetBit(LCD_COM,LCD_E);
При их включении в текст программы, в симуляторе индикатор ничего не показывает, на практике же без них помимо нужных битов в RAM пишется всякий мусор, который, естественно отображается на дисплее. Также возможно потребуется подобрать под конкретный индикатор следующие задержки
...
ClrBit(LCD_COM,LCD_RW);
 NOP();
 NOP();
LCD_DB=data;
...
SetBit(LCD_COM,LCD_E);
  NOP();
  NOP();
ClrBit(LCD_COM,LCD_E);
...
в обеих функциях, ориентировочное время задержки 250-300 нс.

void WriteXY(unsigned char x,unsigned char y,const unsigned char CS)
Установка X Y RAM тут думаю всё понятно.

void init_lcd(void)
Инициализация ЖК для этого устанавливаем указатели X Y в 0, задаём начальную область в данном случае 0 и разрешаем отображение RAM.

void clear(void)
Очистка экрана.

В качестве примера нарисуем мордочку кота, будем надеяться что духу сайта картинка понравится. Обратите внимание что точки рисуются тут не снизу вверх, а слева направо. Листинг основной программы (ks.c):
#include
#include
#include

#define SetBit(x,y) (x|=y)
#define ClrBit(x,y) (x=~y)
#define TestBit(x,y) (xy)

#define LCD_RST 0b00000001
#define LCD_E     0b00000010
#define LCD_RW 0b00000100
#define LCD_RS   0b00001000
#define LCD_CS2 0b00010000
#define LCD_CS1 0b00100000

#define LCD_DB PORTD
#define LCD_COM PORTC

#include "delay.h"
#include "ks0108.h"

void main()
{
DDRC=0xFF;
DDRD=0xFF;
init_lcd();
Delay_ms(10);
clear();
Delay_ms(1);

WriteXY(6,2,LCD_CS1);
Delay_ms(1);
WriteData(0b01000100,LCD_CS1);
WriteData(0b01001000,LCD_CS1);
WriteData(0b11110000,LCD_CS1);
WriteData(0b00001000,LCD_CS1);
WriteData(0b00000100,LCD_CS1);
WriteData(0b01100010,LCD_CS1);
WriteData(0b01100001,LCD_CS1);
WriteData(0b00000010,LCD_CS1);
WriteData(0b00000100,LCD_CS1);
WriteData(0b00001000,LCD_CS1);
WriteData(0b10010000,LCD_CS1);
WriteData(0b01010000,LCD_CS1);
WriteData(0b10010000,LCD_CS1);
WriteData(0b00001000,LCD_CS1);
WriteData(0b00000100,LCD_CS1);
WriteData(0b01100010,LCD_CS1);
WriteData(0b01100001,LCD_CS1);
WriteData(0b00000010,LCD_CS1);
WriteData(0b00000100,LCD_CS1);
WriteData(0b00001000,LCD_CS1);
WriteData(0b11110000,LCD_CS1);
WriteData(0b01001000,LCD_CS1);
WriteData(0b01000100,LCD_CS1);

WriteXY(6,3,LCD_CS1);
WriteData(0b00001000,LCD_CS1);
WriteData(0b00000100,LCD_CS1);
WriteData(0b00000011,LCD_CS1);
WriteData(0b00000100,LCD_CS1);
WriteData(0b00001000,LCD_CS1);
WriteData(0b00010000,LCD_CS1);
WriteData(0b00100000,LCD_CS1);
WriteData(0b01000100,LCD_CS1);
WriteData(0b10001000,LCD_CS1);
WriteData(0b10010000,LCD_CS1);
WriteData(0b10010101,LCD_CS1);
WriteData(0b10010010,LCD_CS1);
WriteData(0b10010101,LCD_CS1);
WriteData(0b10010000,LCD_CS1);
WriteData(0b10001000,LCD_CS1);
WriteData(0b01000100,LCD_CS1);
WriteData(0b00100000,LCD_CS1);
WriteData(0b00010000,LCD_CS1);
WriteData(0b00001000,LCD_CS1);
WriteData(0b00000100,LCD_CS1);
WriteData(0b00000011,LCD_CS1);
WriteData(0b00000100,LCD_CS1);
WriteData(0b00001000,LCD_CS1);

while(1);
}
Вот что у меня получилось:
Усы не очень вышли, но без них кот не кот.
(Если ЭТО - кот, то я - китайский паровоз. Прим. Кота.)
В симуляторе всё работает и радостные и довольные идём подключать индикатор.
Теперь нужно быть особенно бдительным и не запутаться в куче проводков. Особенно не попутайте + и -, я вот на радостях попутал и у меня теперь в столе труп лежит аж 240*128 точек.
ВНИМАНИЕ!!!!!! ТЩАТЕЛЬНО ПРОВЕРЬТЕ ПОДКЛЮЧЕНИЕ ПИТАНИЯ И ОСТАЛЬНЫХ ПРОВОДОВ ПЕРЕД ВКЛЮЧЕНИЕМ.
Подсветку я подключаю через резистор на 15 Ом, можно конечно на прямую 5В подать, но не советую, так на символьном сжёг и он теперь не очень жизнерадостно выглядит.
Контрастность подключаем следующим образом (остальные выводы не показаны для наглядности)
Фото ЖК с включенной подсветкой.
Графика это конечно хорошо, однако текст тоже нужен. Мазохисты могут понабивать шрифт вручную, для остальных я уже набил массив с русским и английским языком плюс различные символы. Лежит это все в массиве sym файла symvol.h, который следует добавить в листинг файла ks0108.h. Также для работы наших функций потребуется здесь же объявить несколько глобальных переменных. Таким образом начало ks0108.h (Для наглядности, вся работа с текстом происходит в файле ks0108_1.h и ks_1.c - будьте внимательны. Прим. Кота.) теперь выглядит так:
#include "symvol.h"

unsigned char
          textx,
          texty,
          curx,
          cury,
          ch[6];
void WriteCom(unsigned char Com,unsigned char CS)
...
Для установки текущего адреса RAM в соответствующем кристалле напишем следующую функцию:
unsigned char gotoxy(unsigned char x, unsigned y)
{
  unsigned char CS, textCS;

  if(x < 10)
{
    CS=LCD_CS1;
    textCS=0;
}
  else
{
    CS=LCD_CS2;
    textCS=64;
}
  WriteXY(x*6-textCS+4,y,CS);

  return CS;
}
Поскольку в области 64*64 может уместиться только 10 целых символов шириной 5 точек с расстоянием в одну точку, текст начинаем выводить с адреса 4,0, иначе символ будет приходиться на границу полуэкрана, функция возвращает значение определённого полуэкрана.
Теперь приступим к функции вывода символов, координаты задаются глобальными переменными textx, texty.
void putc (unsigned char data, unsigned char inv)
{
  unsigned char textL, CS=gotoxy(textx,texty);

  if(data < 0x90)
{
    textL=0x20;
}
  else
{
    textL=0x60;
}

  WriteData((sym[data-textL][0])^inv,CS);
  WriteData((sym[data-textL][1])^inv,CS);
  WriteData((sym[data-textL][2])^inv,CS);
  WriteData((sym[data-textL][3])^inv,CS);
  WriteData((sym[data-textL][4])^inv,CS);
  WriteData(0^inv,CS);

  if(textx < 19)
{
    textx++;
}
  else
{
    textx=0;
    if(texty < 8)texty++;
}
}
Аргумент inv используется для инверсии, если оная не требуется, то устанавливается в 0. Если требуется инверсия, то 0xff. При желании можно инвертировать верхнюю или нижнюю часть символа 0x0f и 0xf0 соответственно. Функция снабжена инкрементом переменной textx, и texty при достижении конца строки. И ещё небольшой нюанс: дело в том что английский алфавит кончается адресом 0x80, таким образом если разобраться
if(data < 0x90)
{
  textL=0x20;
}
else
{
  textL=0x60;
}
здесь мы резервируем адреса 0x80-0x8f т.е. если потребуется сделать дополнительные символы достаточно будет внести их коды в файл symvol.h после буквы z.
Глядим что у нас получилось
Наблюдательный читатель заметил, что букв ё и Ё нет - дело в том что у них коды не лежат в соответствующих диапазонах, если они таки понадобятся, представляю написать их самим, доработав функцию putc.

Для вывода срок напишем функцию puts: void puts (unsigned char str[],unsigned char n,unsigned char inv)
{
  unsigned char a;
  for(a=0;(a






Рекомендуемый контент




Copyright © 2010-2017 housea.ru. Контакты: info@housea.ru При использовании материалов веб-сайта Домашнее Радио, гиперссылка на источник обязательна.