Чем отличается экран lcm12864c от 12864b

от admin

Чем отличается экран lcm12864c от 12864b

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

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

На лицевой стороне имеется защитная плёнка.

На обратной стороне имеется маркировка самого дисплея, выводов интерфейса управления, каждый вывод подписан, также есть построечный резистор VR1, судя по всему это встроенный регулятор контрастности который позволяет не подключать вывод 3 (V0).

Я же буду подключать свой дисплей к микроконтроллеру ATMEGA32 (просто потому что есть и памяти программ хватает для экспериментов)
Писать код буду в Atmel studio 6 которую можно взять на официальном сайте www.atmel.com совершенно бесплатно.
И так, подключаем дисплей по простенькой схемке:

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

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

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

const unsigned char * pic;
extern const unsigned char qweqwe[];

const unsigned char qweqwe[1024] = 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0xFF,0xE0,0x00,0x7F,0xE0,0x00,0x00,0x00,0x03,0xE0,0x00,
0x00,0x00,0x00,0x00,0x03,0xFF,0xF8,0x00,0xFF,0xF8,0x00,0x00,0x00,0x1F,0xE0,0x00,
0x00,0x00,0x00,0x00,0x0F,0xFF,0xFE,0x03,0xFF,0xFC,0x00,0x00,0x00,0xFF,0xC0,0x00,
0x00,0x00,0x00,0x00,0x1F,0xFF,0xFF,0x07,0xFF,0xFE,0x00,0x00,0x03,0xFF,0xF8,0x00,
0x00,0x00,0x00,0x00,0x3F,0xFF,0xFF,0x8F,0xFF,0xFF,0x00,0x00,0x1F,0xFE,0x04,0x00,
0x00,0x00,0x00,0x00,0x3F,0xFF,0xFF,0xEF,0xFF,0xFF,0x80,0x00,0x7F,0xF0,0x0C,0x00,
0x00,0x00,0x00,0x00,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,0x01,0xFF,0x80,0x30,0x00,
0x00,0x00,0x00,0x00,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,0x0F,0xFC,0x01,0xC0,0x00,
0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,0x1F,0xE0,0x0E,0x00,0x00,
0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE0,0x7F,0x00,0x70,0x00,0x00,
0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE0,0xF8,0x07,0x80,0x00,0x00,
0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE1,0xC1,0xF8,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEF,0xFF,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x90,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFC,0x60,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xE3,0xE0,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F,0xE0,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xF8,0xFF,0xE0,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x7F,0xFF,0xFF,0xFF,0xE7,0xFF,0xE0,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xE0,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xE0,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x1F,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x1F,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x1F,0xFF,0xFF,0xFF,0xFF,0xFF,0x80,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0x80,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x07,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x79,0xFF,0xFF,0xFF,0xFF,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x01,0xC1,0xFF,0xFF,0xFF,0xFF,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x0E,0x00,0xFF,0xFF,0xFF,0xFF,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x70,0x00,0x7F,0xFF,0xFF,0xFF,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x03,0xC0,0x00,0x3F,0xFF,0xFF,0xFF,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x01,0x9E,0x00,0x00,0x1F,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x07,0xF0,0x00,0x00,0x07,0xFF,0xFF,0xFF,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x0F,0xC0,0x00,0x00,0x03,0xFF,0xFF,0xFF,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x3F,0xE0,0x00,0x00,0x01,0xFF,0xFF,0xFF,0x80,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0xFF,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0xFF,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xFF,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
>;
// Функция инициализации портов
void init_io(void)
//Порт A на выход
DDRA=0xFF;
PORTA=0x00;
//Порт B на выход
DDRB=0xFF;
PORTB=0x00;
//Порт С на выход
DDRC=0XFF;
PORTC=0x00;
//Порт В на выход
DDRD=0xFF;
PORTD=0x00;
>
// Функция отправки 1 на дисплей
void SendSPI_1 (void)
PORTC|=(1<<SID);
_delay_us(250);
PORTC|=(1<<SCLK);
_delay_us(250);
PORTC&=

Для примера выведу на дисплей рамку в режиме basic instruction.
Вот как это выглядит:

Потом переключаю дисплей в режим графики extended instruction и сразу же вижу много мусора в памяти дисплея которую надо очистить или можно сразу вывести графическое изображение. Я решил очистить дисплей при помощи функции QC12864_clear_graph.

Мини-панель приборов на дисплее LCM12864 и ATmega64

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

  • индикации текущего времени с применением более точной микросхемы RTC DS3231 (на Ali)
  • измерения температуры двигателя с помощью датчика PT-100 (на Ali)
  • измерения температуры окружающего воздуха с помощью DS18B20 или с помощью датчика температуры, встроенного в микросхему реального времени
  • измерения напряжения бортовой сети (со шкалой) 7 — 16В
  • измерения частоты вращения коленчатого вала двигателя (со шкалой) 300 — 9900 об/мин
  • измерения скорости движения 0 — 255 км/ч
  • одометры: суточный с возможностью сброса, и общий; запись в энергонезависимую память микроконтроллера

Шрифты, отображающие температуру и обороты двигателя увеличены, а часов — уменьшены.

Так же устройство имеет дополнительные функции, такие как

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

звуковые и визуальные:

  • индикация включенных указателей поворота
  • предупреждение о слишком низком или недопустимо высоком напряжениях бортовой сети
  • предупреждение о перегреве двигателя
  • есть возможность отключить звук
  • программная калибровка вольтметра
  • установка верхнего и нижнего порогов предупреждений для контроля напряжения бортовой сети
  • установка порога предупреждения о перегреве двигателя
  • настройка параметров «длина окружности колеса» и «кол-во магнитов» для датчика скорости мотоцикла; для автомобильного датчика «длина окружности колеса» устанавливается 100 см, а «кол-во магнитов» — количество импульсов на 1 метр
  • установка значения «импульс/оборот» для тахометра, и возможность указать максимальные обороты, при которых шкала будет полностью заполнена
  • установка уровня яркости подсветки для дневного и ночного времени

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

Схема уже довольно большая, но на самом деле ничего сложного в ней нет.

Основа — микроконтроллер ATmega64, вывод информации — графический дисплей 128х64 точек с контроллером KS0108 и звуковой излучатель типа 1212FXP обязательно со встроенным генератором. Питание цифровых элементов — на стабилизаторе 7805, микроконтроллер питается отдельно (линия U1_VCC) через диод Шоттки D2, и в момент отключения питания от бортовой сети, срабатывает детектор выключения на R1 и R2 — программа обработки прерывания INT5 записывает значения одометров в энергонезависимую память. В это время микроконтроллер питается энергией, накопленной конденсатором C4. Все остальное — обработка входящих сигналов транспортного средства, кратко о них в статье предыдущей версии. JP1 — джампер переключения в режим программирования — во время прошивания МК вывод PEN нужно подтянуть к GND. Разъём J1 ISP — для внутрисхемного программирования. Фьюзы выставляются следующим образом:

По фьюзам хочу дать совет тем, кто мало знаком или впервые работает с AVR микроконтроллерами. Чтобы не «запороть» камень, в любой программе (PonyProg, Khazama AVR Programmer и т.п.), делается так: сначала считываем фьюзы, смотрим, отмечен ли SPIEN галочкой; если да, то фьюзы ставим как на картинке в статье, если нет — выставляем инверсно. Правильно собранная схема с прошитым микроконтроллером в настройке не нуждается и запускается сразу. Разве что нужно покрутить RV1 для установки контрастности дисплея и RV2 для калибровки датчика температуры двигателя. Для этой цели был выбран датчик PT-100, — стоит он недорого, позволяет измерять, в отличие от DS18B20, температуры более +125°С и выглядит примерно так:

Измерение температуры окружающего воздуха (или если кому надо — внутри салона) может осуществляться двумя способами: с помощью встроенного в микросхему часов датчика или внешнего DS18B20. Чтобы измерять датчиком из DS3231, на разъем ISP нужно поставить перемычку (джампер) как на фотографии, подтянув линию TEMP_SENS к GND. Для измерения цифровым внешним датчиком, его нужно подключить к тому же разъему программирования (ISP) согласно полярности (VCC, GND), а линию TEMP_SENS (на ISP она совпадает с MOSI) к выводу DQ датчика.

Печатная плата изготавливается из двухстороннего фольгированного текстолита.

Кнопки располагаются на отдельной плате со шлейфом и разъемом для подключения:

Управление осуществляется следующим образом. В основном режиме:
— кнопка M/SEL/ HR при длительном удержании вводит устройство в режим установки времени — часы устанавливаются этой же кнопкой, минуты — ENT/+/ MIN .
— кнопка ENT/+/MIN при коротком нажатии сбрасывает суточный одометр, но не сразу. На месте счетчика появляется вопрос «Сброс?», подтверждаем кнопкой M/SEL/HR. Если не подтвердить, то через 3-4 секунды устройство вернется в нормальный режим. Общий одометр сбросить кнопками нельзя. Если нужно обнулить или выставить начальное значение пробега, надо считать программатором EEPROM из микроконтроллера, общий пробег содержится в 4-х байтах, начиная с 16-й ячейки (выделено красным):

При этом они расположены от младшего к старшему. То есть если брать пример с картинки выше, в красном прямоугольнике записано число 01 6A (00 00 01 6A) в шестнадцатеричном формате, что соответствует десятичным 362 км пробега. Редактируем считанный файл EEPROM, выставляя нужный пробег. Прошиваем.
— кнопка » » при коротком нажатии включает-выключает звук на устройстве. При выключенном звуке справа от часов появляется значок перечеркнутого динамика.

Чтобы попасть в меню настроек, нужно произвести включение устройства с зажатой кнопкой M /SEL/HR:

выбор пункта осуществляется той же кнопкой M/ SEL /HR
вход в выбранный пункт — с помощью ENT /+/MIN
установка параметра с помощью ENT/ + /MIN и » «

При первом входе в меню некоторые значения могут быть 255 или 65535 — это следствие того, что ячейки энергонезависимой памяти еще пусты. Нужно установить адекватные параметры настроек и выйти из меню выбрав пункт «Сохранить и выйти».

К статье прикреплены 2 архива. Первый содержит прошивки для версий устройства со спидометром-одометром и без них, проект Proteus, файл печатной платы в формате LAY. Второй содержит прошивку, печатную плату и проект для этого же устройства, только с дисплеем разрешением 192×64 точек. Места на нем предостаточно, поэтому шкала и цифры тахометра и скорости, заметно больше:

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

Чем отличается экран lcm12864c от 12864b

Подключение LCD экрана WG12864B (KS0108) к Arduino

Всем привет!
Настоящая инструкция является вольным переводом известной статьи, расположенной на портале Arduino.cc.

Вариант A:
HDM64GS12L-4
Crystalfontz CFAG12864B
Sparkfun LCD-00710CM
NKC Electronics LCD-0022
WinStar WG12864B-TML-T

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

250 Ом. Пример подключения экранчика к плате Arduino:

Работа с графическим дисплеем WG12864 на базе контроллера KS0107

Обычно для вывода информации сигнального дисплея на HD44780 более чем достаточно. Но иногда нужно нарисовать картинку, график или хочется сделать красиво, с модными менюшками. Тут на помощь приходят графические дисплеи. Одним из самых простых и доступных является дисплей на контроллере KS0107 или аналоге. Например, WG12864A от Winstar. Сам дисплей вполне свободно достается, имеет довольно большой размер (диагональ около 80мм) и разрешение 128х64 пикселя. Монохромный. Цена вопроса 400-500р.

Подключение
Управление дисплеем параллельное. Есть шина данных и линии задания направления и вида данных. Это, кстати, один из минусов — требует очень много проводов управления. Занимает почти 16 линий. Но зато и очень прост в работе.

Итак, если взять тот, что у меня WG12864A-TGH-VNW то у него следующая распиновка:

  • Vdd и Vss это питание, оно у него пятивольтовое.
  • Vee — источник отрицательного напряжения. Там примерно минус 5 вольт. Есть не на всех моделях этих дисплеев, у Winstar о наличии такой фенечки говорит буква V в маркировке. WG12864A-TGH-VNW
  • Vo — напряжение регулировки контраста. Туда подается либо 0…5 вольт, либо от -5 до 5, в зависимости от модели и температурного диапазона. Обычно более морозостойкие дисплеи требуют отрицательное напряжение. Схема включения простая:
  • D/I — Данные/команда. Логический уровень на этом выводе определяет предназначение кода на шине данных. 1 — данные, 0 — команда.
  • R/W — Чтение/Запись. Уровень на этой ноге задает тип действия. 1 чтение, 0 запись.
  • Е — Строб, синхронизирующий импульс. Дрыг этой вожжи вверх-вниз проворачивает шестеренки в интерфейсе контроллера.
  • DB0..7 — Шина данных, на которую мы выдаем нужный нам код.
  • CS1 и CS2 — выбор контроллера.
  • RST — сигнал сброса. Ноль на этой линии сбрасывает контроллеры в ноль. Но не сбрасывает видеопамять, только текущую адресацию.
  • A и K — питание светодиодной подсветки. Там, как правило, обычные светодиоды, так что напрямую туда 5 вольт подавать нельзя. Только через ограничительный резистор. Ток потребления подсветки весьма велик, около 200мА, падение напряжения в районе 4 вольт. На пяти вольтовом питании ограничетельный резистор должен быть порядка 5-10 Ом.

К контроллеру (ATMega16 на Pinboard) я подключил все следующим образом.

Данные полностью легли на PORTA, а управление на PORTB. В качестве резистора подстройки контраста я взял многооборотный переменник, что так кстати стоит рядом для подобных случаев. Питание подсветки взял с колодки от дисплеяя. Благо там все уже готово, даже управление от транзистора есть 🙂 Правда я ее просто включил.

Читать:
Как подключить цифровую камеру к аналоговому регистратору

Двое из ларца, одинаковых с лица. Адресация
Контроллер CS0107 он может организовать матрицу только 64х64. А у нас в дисплее вдвое большая 128х64. Значит стоят два контроллера. Один отвечает за правую половину экрана, другой за левую.
Он представляет собой этакую микросхему памяти, где все введенные данные отображаются на дисплее. Каждый бит это точка. Кстати, для отладки удобно юзать, выгружая туда разные данные, а потом разглядывая этот дамп). Карта дисплея выглядит так:

Байты укладываются в два контроллера страницами по 64 байта. Всего 8 страниц на контроллер.

Так что для того, чтобы выставить точку с координатами на экране, например, Х = 10, Y=61 надо вычислить в каком контроллере она находится. Первый до 63, второй после, если адрес во втором контроллере, то надо вычесть 64 из координаты. Затем вычислить страницу и номер бита. Страница это Х/8, а номер бита остаток от деления (Х%8). Потом нам надо считать нужный байт из этой страницы (если мы не хотим затронуть остальные точки), выставить в нем наш бит и вернуть байт на место.

Протокол обмена
Тут все просто, без каких либо изысков. Выставляем на линиях RW, DI что мы хотим сделать, линиями CS1 и CS2 выставляем к кому обращаемся. На шину данных выдаем нужное число и поднимаем-опускаем линию строба. Опа! Впрочем, есть одна тонкость. Для чтения данных строб нужно дернуть дважды, т.к. предварительно данные должны попасть в регистр-защелку. Для чтения же флага состояния такой изврат не нужен. Вот примеры временных диаграм для разных режимов.

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

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

Временные диаграммы, т.е. сдвиг фронтов между собой по времени может быть разным у разных контроллеров. Где то быстрей, где то медленней. Но в целом 1мкс обычно хватает. В реале обычно меньше. Лучше поглядеть в даташите на конкретный контроллер (не дисплей, в ДШ на дисплей обычно редко есть описание самого контроллера). Там обычно есть таблица вида:

Где указаны максимально допустимые временные интервалы. Если они будут меньше или больше, то дисплей скорей всего не будет работать. Или будет работать с ошибками. Если у вас на дисплей в процедуре заливки или очистки экрана полезли всякие левые пиксели и прочие артефакты — значит тайминги не выполняются. Также рекомендую проверять тайминги на чтение и на запись. Делается это просто — гоним последовательно сначала чтение, а потом запись обратно. Если ничего не изменилось — значит все ок. Появились искажения? Крутите временные задержки. Только рекомендую читать не пустоту вида 0х00, а что нибудь более веселое залить, например, шахматную доску из пикселей. По очереди 0х55 и 0хАА.

Система команд.
Она тут простейшая.

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

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

У меня ициализация, по командам, выглядит так:

  • 0x3F — включить
  • 0x40 — Адрес Y=0
  • 0xB8 — Страница Х=0
  • 0xC0 — Скролл = 0 (т.е. с самого верха)

Ну и потом еще заливка сразу в оба контроллера.

Код
Итак, приступим к коду. Чтобы было наглядней я все операции с ногами расписал в виде макросов. Заодно будет гораздо проще все перенести на другую архитектуру. Просто написав другие макросы, не правя сам код 🙂
Весь код можно поглядеть в нашей кодосвалке:
lcd_wg128.h
lcd_wg128.c

Покажу тут лишь характерные моменты работы с дисплеем.

Записью команд и данных занимаются следующие функции:

Чтение слова состояния делать не стал. Т.к. дисплей работает весьма шустро, что на круг ожидания можно не уходить, а просто подождать несколько тактов. Собственно этих трех функций уже достаточно для работы 🙂 Остальное все свистоперделки и удобства.

Вроде заливки экрана:

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

// Процедура установки пикселя. Т.к. пиксель часть байта, то надо сначала вычислить // Контроллер, потом страницу и нужный байт. Считать этот байт. Изменить в нем только один, // нужный, бит и вернуть его на место. // На входе координаты и режим обработки пикселя (вкл, выкл, переключение) void PIXEL(u08 x,u08 y,u08 mode) < u08 CSS, row, col, byte; u08 res,read; if(y>63) // Проверяем в каком контроллере искомый пиксель < CSS = 1<<CS2; // Если У больше 63 значит во втором. Выставляем 2й col = y-64; // И отнимаем смещение, чтобы не мешалось. >else < CSS = 1<<CS1; // Иначе контроллер у нас первый. col = y; // А смещения нет. >row = x>>3; // Делим Х на 8, чтобы получить номер страницы. byte = 1<<x%8; // А остаток от деления даст нам искомый бит, который мы задвигаем // и получаем нужную нам битмаску для модификации байта. SET_ADDR(row,col,CSS); // выставляем адрес read = LCD_RD_DATA(CSS); // Читаем данные (адрес при этом ++ аппаратно). switch(mode) // В зависимости от режима < case 0: // Clear < res = read &

byte; // Накладываем сбрасывающую (NOT) маску break; > case 1: // Invert < res = read ^ byte; // Накладываем инвертирующую (ХОR) маску break; >default: // Set < res = read | byte; // Накладываем устанавливающую (OR) маску break; >> SET_ADDR(row,col,CSS); // Повторно выставляем адрес. Т.к. чтение его исказило. LCD_WR_DATA(res,CSS); // Вгоняем туда результат нашей модификации. >

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

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

// Запись сразу блока. Удобно для вывода строк или картинок, постранично. // На входе страница Х и колонка У. А также длина блока и адрес откуда брать данные. u08 BLOCK(u08 x,u08 y, u08 len, u16 addr) < u08 CSS,i,col; if(y>63) // Сначала вычисляем нужные нам сегмент (чип) < CSS = 1<<CS2; col = y-64; >else < CSS = 1<<CS1; col = y; >SET_ADDR(x,col,CSS); // Ставим адрес // А дальше в цикле гоним байты. Не забывая увеличивать адрес, чтобы была выборка из // памяти. Счетчик, чтобы не сбиться со счета. И номер колонки, чтобы не вылезти за границы // И вообще понимать где мы находимся. for(i=0;i!=len;i++,addr++,col++) < if(64==col) // Попутно проверяем за границы выхода из сегмента < if(CSS == (1<<CS2)) // Если случилось, и у нас второй сегмент, т.е. конец < // страницы (уже второй в этой строке) return 128; // выходим с кодом ошибки (код больше разрешения экрана) >col=0; // Иначе же обнуляем счетчик колонок. И переключаем банку CSS = 1<<CS2; // Выбрав второй сегмент экрана SET_ADDR(x,col,CSS); // И выставив новый текущий адрес > LCD_WR_DATA(pgm_read_byte(addr),CSS); // Пишем туда данные прям из флеша (таблица символов). > return y+len; // Возвращаем координату увеличиную на размер блока. >

Блочный вывод легко превращается в текстовый вывод. Надо лишь совместить таблицу символов с печаталкой блоков. И гнать данные из флеша напрямую.

// Процедура вывода строки. На входе строка, и координаты. Х в страницах, а У в точках. void LCD_putc(u08 x,u08 y,u08 *string) < u08 sym; while (*string!='\0') // Пока первый байт строки не 0 (конец ASCIIZ строки) < if(127<y) // Проверяем за границу выхода за экран. Если вылезаем < // Вот тут, кстати, можно поиграть с числом, чтобы не рубило последний символ. y=0; // То обнуляем координату точки. x++; // Выставляем следующую строку if(x>7) break; // Если экран и вниз кончился - выход. >sym = *string-0x20; // Вычисляем из ASCII кода смещение в таблице символов. // Для русского языка и цифр надо условия добавить. Т.к. // таблица там не полная, не 255 байт. y = BLOCK(x,y+1,5,(u16)symboltable+sym*5); // Закатываем этот блок. string++; // Не забывая увеличивать указатель, > >

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

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

Ну и, традиционно, архив с примером. Сделано все на ATmega16 под WinAVR GCC на Pinboard

  • Пример кода для AVR
  • Пример кода для PIC24 от Chiesel. В ее состав входят файлы «KS0108.c», «KS0108.h», «font_set_6x6_v2.h». В файлах «KS0108test.c» (файл прошивки: «Presentation.hex») и «flying_cursors.c» (файл прошивки: «Flying.hex») представлены примеры работы библиотеки.)

Спасибо. Вы потрясающие! Всего за месяц мы собрали нужную сумму в 500000 на хоккейную коробку для детского дома Аистенок. Из которых 125000+ было от вас, читателей EasyElectronics. Были даже переводы на 25000+ и просто поток платежей на 251 рубль. Это невероятно круто. Сейчас идет заключение договора и подготовка к строительству!

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

115 thoughts on “Работа с графическим дисплеем WG12864 на базе контроллера KS0107”

Зачетно
Надо бы свой прикрутить, попробовать, а то валяется на полке.
Цены на них откровенно безбожные, учитывая, что TFT 2.4″ у китайцев стоят 20$.
Кстати, удобно еще генерить массив какой-нибудь прогой, потом просто выводить на экран. Я с tic-ами там делал. Для статичной фигни.

TFT так просто не обработаешь, под него нужен мощный контроллер, а лучше ПЛИС и видеопамять. Так что не все так просто.

Можно да, но его надо гдето в памяти держать. Тут получается килобайт только фреймбуфер.

Контроллер обычно в таком дисплее есть.
Видеопамяти все равно не напасешься, особенно с двойным буфером.
К примеру, для 7″ (800х480) дисплея с глубиной цвета 24 бит, нужен мегабайт с лишним памяти. RAMа больше 128К я вроде не видел в МК.
Но в целом да, ресурсы все равно нужны свободные.

Мощный то и не нужен, lpc2478 или lh79520 отлично справятся, только если хранить картинки нужно, то лучше прикрутить внешний nand мега на 4

Ди, нескромный вопросик, а с чем у тебя связана работа? 🙂

Я уже три года как безработный О_о

А последняя работа была какая?
Ди. Раз ты тут. Скажи своей жене чтобы она занялась моим заказом 🙂 701 вроде.

Последний раз я был наладчиком лабораторного оборудования. До этого наладчиком станков ЧПУ, а до этого я был студентом 🙂

Похожие статьи