Объявление

Внимание!
Данный форум предназначен только для радиолюбителей!
Никакие прочие объявления, реклама товаров либо услуг невозможны!


Любой спам на нашем форуме запрещён!
Разрешаются только ссылки по темам! 3а нарушения БАН.


Работа с графическим дисплеем SSD1298

Правила форума
Внимание! Любой спам на нашем форуме запрещён!
Коммерческая реклама сайтов, ссылки, спам запрещены. Так же запрещены ссылки на сайты в профилях новичков.
Бан без предупреждений.

Работа с графическим дисплеем SSD1298

Сообщение admin » 27 ноя 2016, 20:20

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


Данная статья преследует цель рассмотреть нюансы управления большим цветным LCD при помощи микроконтроллера серии STM8. Рассматривать будем на примере дисплея китайского производства типа SX-TG280SDCPET00 с контроллером SSD1298 и STM8L162S8T6. Дисплей данный был выдран из игровой приставки QUMO GameBox LE. Вот такой:
Изображение

Дисплей может называться и по-другому. Главное – чтоб контроллер в нем был SSD1298. Да и код можно легко портировать куда угодно, благо на Си написан.


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


Описание дисплея и его контроллера
Дисплей с контроллером SSD1298 представляет собой удобный для крепления и пайки законченный модуль с гибким шлейфом. К основной плате устройства он соединяется методом пайки 37-ми контактов.

Разрешение: 320*240 точек
Размер видимой области: 58*49 мм
Общий размер модуля: 50*70 мм.



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

Запуск дисплея
Порядок следующий


1. Произвести аппаратный сброс контроллера подачей низкого логического уровня на вход /RESET дисплея;

Код: выделить все
delay_ms(100);  // Выжидаем некоторое время (может потребоваться на больших частотах)
LCD_RES = 1;    // Деактивируем аппаратный сброс, который был активирован при настройке портов МК


2. Настроить внутренние регистры конфигурации:

Код: выделить все
 // Теперь записываем данные для настройки контроллера дисплея
  // Эти параметры я брал в интернете. Сначала происходит настрока внутреннего преобразователя
  // для питания стекляшки. Эти параметры я менять не советую.
  LCD_WriteReg(0x0028, 0x0006);     // VCOM OTP
  LCD_WriteReg(0x0000, 0x0001);     // Oscillation start
  LCD_WriteReg(0x0003, 0xaea4);     // power control 1---line frequency and VHG,VGL voltage
  LCD_WriteReg(0x000c, 0x0004);     // power control 2---VCIX2 output voltage
  LCD_WriteReg(0x000d, 0x000c);     // power control 3---Vlcd63 voltage
  LCD_WriteReg(0x000e, 0x2800);     // power control 4---VCOMA voltage VCOML=VCOMH*0.9475-VCOMA
  LCD_WriteReg(0x001e, 0x00b5);     // POWER CONTROL 5---VCOMH voltage
 
  // Следующие параметры описаны в ДШ на стр. 30-31. Они определяют порядок
  // сканирования строк, порядок вывода цветов и др.
  LCD_WriteReg(0x0001, 0x3B3F);     // Driver Output Control
 
  // Следующую строку также менять не советую
  LCD_WriteReg(0x0002, 0x0600);     // LCD Drive AC Control
 
  // Регистр управления режимом Sleep. Может понадобиться для устройств с батарейным
  // питанием Для справки: Дисплей потребляет от 2,5 до 8 мА в активном режиме
  // и от 70 до 300 мкА в спящем (стр. 63 ДШ)
  LCD_WriteReg(0x0010, 0x0000);     // Sleep Mode
 
  // Режим позиционирования и направления сканирования дисплея.
  // Для данных значений при расположении дисплея в Landscape контроллер справа
  // нижний левый угол будет иметь координаты 0,0
  // Я такие значения применил для удобства вывода изображений из BMP файлов
 
  // Более подробно по данной установке можно прочитать на стр. 43-46 ДШ
  LCD_WriteReg(0x0011, 0x6838);  // Entry Mode


Вот регистр с адресом 0x0011 представляет большой интерес. Он позволяет управлять дисплеем в зависимости от его положения в устройстве.
Ниже вырезка из ДШ с указанием названий битов:

Изображение

За ориентацию и направление «развертки» отвечают биты AM, ID0 и ID1.
В зависимости от их значения сканирование и вывод данных из экранного ОЗУ будет выводиться по следующим алгоритмам:

Изображение

Значение в моих исходниках установлено для Landscape режима (шлейф справа). Для Portrait положения дисплея строка будет иметь вид LCD_WriteReg(0x0011,0x6830); Шлейф в таком случае должен располагаться снизу.

Код: выделить все
  // Не нашел этих параметров в ДШ, но переписывать не стал...
  LCD_WriteReg(0x0005, 0x0000);  // ???
  LCD_WriteReg(0x0006, 0x0000);  // ???
  LCD_WriteReg(0x0016, 0xef1c);  // ???
 
// Следующие настройки можно посмотреть на стр. 39 ДШ. Я их не использую и не пробовал,
//т.к. нет надобности.
  LCD_WriteReg(0x0007, 0x0033);  // Display control 1
    /* when GON=1 and DTE=0,all gate outputs become VGL */
    /* when GON=1 and DTE=0,all gate outputs become VGH */
    /* non-selected gate wires become VGL */
 
  // Далее расположены настройки размера видимой области дисплея. Их можно менять
  // по ходу работы при необходимости вывода в определенную область экрана
  LCD_WriteReg(0x000b, 0x0000);  // Frame Cycle Control
  LCD_WriteReg(0x000f, 0x0000);  // Gate Scan Start Position
 
  // По следующим двум строкам ничего не подскажу – прокрутку не использовал…
  LCD_WriteReg(0x0041, 0x0000);  // Vertical Scroll Control 1
  LCD_WriteReg(0x0042, 0x0000);  // Vertical Scroll Control 2


По следующему коду тоже сказать ничего не могу. Не использовал эту возможность. Из чтения ДШ сделал вывод, что эти регистры используются при делении дисплея на 2 части.

Код: выделить все
LCD_WriteReg(0x0048, 0x0000);  // First Window Start
  LCD_WriteReg(0x0049, 0x013f);  // First Window End
  LCD_WriteReg(0x004a, 0x0000);  // Second Window Start
  LCD_WriteReg(0x004b, 0x0000);  // Second Window End


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

Для пояснения процесса вывода в ДШ есть вот такое изображение:

Изображение

Код: выделить все
LCD_WriteReg(0x0044, 0xef00);  // Horizontal RAM start and end address
  LCD_WriteReg(0x0045, 0x0000);  // Vertical RAM start address
  LCD_WriteReg(0x0046, 0x013f);  // Vertical RAM end address


Счетчики строк и столбцов. Я их меняю функцией LCD_SetCursor. При запуске, ясное дело, устанавливаются в 0, чтоб рисовать с начального адреса видео ОЗУ.

Код: выделить все
 LCD_WriteReg(0x004e, 0x0000);  // Set GDDRAM X address counter
  LCD_WriteReg(0x004f, 0x0000);  // Set GDDRAM Y address counter


3. Настройки регистров гамма-коррекции. Для предотвращения искажения цвета не рекомендую менять их. Данные значения я выдрал из какого-то универсального драйвера. И в ДШ их не нашел, в инете на данный контроллер тоже.

Код: выделить все
LCD_WriteReg(0x0030,0x0707);
  LCD_WriteReg(0x0031,0x0202);
  LCD_WriteReg(0x0032,0x0204);
  LCD_WriteReg(0x0033,0x0502);
  LCD_WriteReg(0x0034,0x0507);
  LCD_WriteReg(0x0035,0x0204);
  LCD_WriteReg(0x0036,0x0204);
  LCD_WriteReg(0x0037,0x0502);
  LCD_WriteReg(0x003a,0x0302);
  LCD_WriteReg(0x003b,0x0302);
  LCD_WriteReg(0x0023,0x0000);
  LCD_WriteReg(0x0024,0x0000);
  LCD_WriteReg(0x0025,0x8000);
  LCD_WriteReg(0x0026,0x7000);
  LCD_WriteReg(0x0020,0xb0eb);
  LCD_WriteReg(0x0027,0x007c);


Перечисленные настройки (те, которые я использовал) уже позволяют формировать на экране дисплея изображения, отображать текст. Ввиду наличия у меня медленного контроллера я не пытался вывести видео и использовать дисплей полностью, со всеми его возможностями.
После выполнения вышеописанного кода на экране должен появиться «мусор» из случайным образом засвеченных точек. Для того чтоб очистить экран необходимо очистить содержимое экранного ОЗУ контроллера. За это у нас отвечает функция LCD_Clear(unsigned int Color);


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

Код: выделить все
//Обзываем линии шины данных для удобства
#define LCD_CS  PH_ODR_bit.ODR4
#define LCD_RS  PH_ODR_bit.ODR5
#define LCD_WR  PH_ODR_bit.ODR6
#define LCD_RD  PH_ODR_bit.ODR7
#define LCD_RES PD_ODR_bit.ODR4
 
// Процедура записи адреса регистра
void LCD_WriteIndex(unsigned int index)
{
  LCD_RS = 0;       // Тип данных - команда (в данном случае адрес)
  LCD_RD = 1;       // При записи RD должен быть стопудово равен 1, а то не запишет
  PB_ODR = (index & 0x00FF);      // Выставляем младшую часть адреса на шину
  PF_ODR = ((index & 0xFF00) >> 8);   // и старшую
  LCD_WR = 0;       // Следующие три строки - строб /WR
  delay_us(5);
  LCD_WR = 1;
}
 
// Процедура записи данных в регистр или ОЗУ
void LCD_WriteData(unsigned int data)
{
  LCD_RS = 1;          // Тип данных - данные
  PB_ODR = (data & 0x00FF);    // Вывод на шину старшего
  PF_ODR = ((data & 0xFF00) >> 8);     // и младшего байтов данных
  LCD_WR = 0;          // Строб
  delay_us(5);
  LCD_WR = 1;
}


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

Код: выделить все
<code>
// Процедура записи данных в регистр
// Очень полезна при инициализации
void LCD_WriteReg(unsigned int LCD_Reg, unsigned int LCD_RegValue)
{
  LCD_CS = 0;         // Активируем Chip Select
  LCD_WriteIndex(LCD_Reg);   // Пишем адрес регистра
  LCD_WriteData(LCD_RegValue);   // Пишем в него данные
  LCD_CS = 1;         // Деактивируем Chip Select
}


Она, кстати, и используется в инициализации. Как Вы ее пропишете, конечно, зависит от Ваших привычек в программировании. Я всё разместил в одном файле. Кто-то может поделить или в хидер прописать.

Код: выделить все
// Функция очистки дисплея заливает весь экран цветом, указанным в аргументе Color
void LCD_Clear(unsigned int Color)
{
  unsigned long index=0;
  LCD_SetCursor(0,0);      // Устанавливаем курсор в начало
  LCD_CS = 0;         // Здесь запись организована "атомарно" для ускорения процедуры
  LCD_WriteIndex(0x0022);    // Запись этого адреса в регистр индекса означает, что
                             // сейчас будут выводиться данные в экранное ОЗУ
                             // Как себя будут вести счетчики строк и столбцов определяется
                             // регистром с адресом 0x0011
  for(index=0;index < 0x12C00;index++)
   {          // цикл с количеством итераций 320*240
       LCD_WriteData(Color);    // ставим точки заданного цвета
    }
  LCD_CS = 1;               // Отцепляемся от дисплея
}


Засветка точки осуществляется записью в регистр 0x0022 кода цвета точки.


Координаты засвечиваемой точки определяются содержимым регистров 0x004e и 0x004f (см. выше). После записи точки счетчики адреса автоматически обновляются согласно установленным правилам (регистр 0x0011, см. выше).


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


Если дисплей поддерживает чтение данных из области видео ОЗУ, возможно чтение содержимого экрана в контроллер. Я не использовал такой возможности опять же из-за низкой рабочей частоты МК, но хотелось бы для нормального отображения букв на цветном фоне.


Подключение дисплея
Мой экземпляр дисплея имеет 16-битную шину данных и шину управления с 5 линиями, но сам контроллер дисплея имеет несколько вариантов шин (16 и 8 бит параллельная;16, 9 и 8 бит последовательная), тип которых выбирается замыканием соответствующих линий на землю. Эти линии замкнуты на гибком шлейфе дисплея и, скорее всего, изменить тип шины не удастся.


С целевой платформой дисплей соединяется посредством пайки 37-ми контактов:

Изображение

Поясню их назначение:
DB00-DB15 – шина данных;
/CS – Chip Select;
RS (DC по даташиту) – команда / данные;
/WR – строб записи;
/RD – строб чтения;
/RESET – аппаратный сброс;
IM0, IM3 – выводы конфигурации шины;
Y-,Y+,X-,X+ — выводы тачскрина;
LEDA, LEDK1-LEDK4 – выводы диодов подсветки;
VDD – питание;
GND – земля.



Взаимодействие с дисплеем может осуществляться при низком логическом уровне на его выводе /CS . По шине данных мы передаем на контроллер команды и данные и можем считывать его байт состояния, тип контроллера и данные, записанные в экранную область ОЗУ контроллера.


Выбор типа передаваемых данных осуществляется установкой вывода RS в соответствующее состояние (команда – 0, данные – 1). Передача данных/команд в дисплей сопровождается стробом линии /WR, чтение – стробом /RD. Вывод аппаратного сброса /RESET предназначен для установки в начальное состояние всех регистров управления контроллера дисплея (но не данных в экранном ОЗУ!) после подачи на него питания (по линиям VDD, GND).


В ДШ есть изображение, объясняющее принцип общения с дисплеем:

Изображение

Как видно из рисунка, для обращения к дисплею используется немного другой алгоритм – обращение по стробу /CS. У меня же – Стробом /WR или /RD. Я пробовал и так и так – работает, так что тут Вы вольны выбирать сами. Вывод E (OE) у меня не выведен на шлейф, но это не принципиально.


Итог
Для вывода точки необходимо инициализировать дисплей:
произвести аппаратный сброс
заполнить регистры конфигурации начальными значениями.
Затем установить счетчики адреса экранного ОЗУ в необходимое состояние
записать в индексный регистр адрес 0x0022 (функцией LCD_WriteIndex(unsigned int index))
вывести данные, соответствующие цвету точки.



Хочу предупредить об одном подводном камне. Не планируя читать данные из дисплея я поначалу не развел плату под вывод /RD, и не смог запустить дисплей. После, установив стабильный логический уровень на этом выводе, получил и стабильную работу. Не оставляйте висеть рабочие выводы!


С выводами подсветки дисплея все просто – тут имеется 4 светодиода с общими анодами и разделенными катодами. Для их включения необходимо применить гасящие резисторы. Я установил 4 резистора по 68 Ом (питание – 3,3 в) и яркости мне хватает.


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


Отдельного внимания заслуживают выводы IM0 и IM3 – именно с их помощью выбирается тип шины дисплея. Тут есть нюанс. Выводы могут быть подключены к контроллеру дисплея, а, в моем случае, нет. То есть я не могу поменять 16 разрядную шину на 8-ми. В Вашем случае они могут быть подключены, что нетрудно выяснить, проследив дорожки от выводов к контроллеру. Выбор типа шины и тайминги хорошо описаны в даташите на контроллер.


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

Изображение

Ввиду того, что шина моего дисплея имеет ширину 16 бит мне пришлось задействовать под это дело 2 порта микроконтроллера. В моем случае это порты B и F. Под линии шины управления у меня отведены старшая тетрада порта H и линия порта D. Линии выбраны из-за удобства разводки печатной платы.

Изображение

Как видите, схема до безобразия проста.


Описание протокола взаимодействия
Итак, я упоминал, что подключать данный дисплей мы будем к МК семейства STM8L. При написании своих программ я не использую библиотек от STM. Не знаю, плохо это или хорошо, но мне так удобнее. Тем более, что при таком подходе обращения к портам становятся прозрачными и любители AVR и тому подобных PIC’ов смогут легко переписать код под свои нужды и камни. В принципе, код прокомментирован, по большей части разобран выше и прост, так что, настроить порты особого труда не составит.
Работа с дисплеем SSD1298:
Код: выделить все

//Обзываем линии шины данных для удобства

#define LCD_CS  PH_ODR_bit.ODR4

#define LCD_RS  PH_ODR_bit.ODR5

#define LCD_WR  PH_ODR_bit.ODR6

#define LCD_RD  PH_ODR_bit.ODR7

#define LCD_RES PD_ODR_bit.ODR4

 

// Процедура записи адреса регистра

void LCD_WriteIndex(unsigned int index){

  LCD_RS = 0; // Тип данных - команда (в данном случае адрес)

  LCD_RD = 1; // При записи RD должен быть стопудово равен 1, а то не запишет

  PB_ODR = (index & 0x00FF);  // Выставляем младшую часть адреса на шину

  PF_ODR = ((index & 0xFF00) >> 8); // и старшую

  LCD_WR = 0; // Следующие три строки - строб /WR

  delay_us(5);

  LCD_WR = 1;

}

 

// Процедура записи данных в регистр или ОЗУ

void LCD_WriteData(unsigned int data){

  LCD_RS = 1; // Тип данных - данные

  PB_ODR = (data & 0x00FF); // Вывод на шину старшего

  PF_ODR = ((data & 0xFF00) >> 8);  // и младшего байтов данных

  LCD_WR = 0; // Строб

  delay_us(5);

  LCD_WR = 1;

}

 

// Процедура чтения данных из регистров и ОЗУ

unsigned int LCD_ReadData(void){

  unsigned int value=0;

  LCD_RS = 1; // Тип данных - данные

  LCD_WR = 1; // Вывод записи должен быть стопудово в 1

  PB_DDR = 0x00;  // Переводим шину данных на ввод

  PF_DDR = 0x00;

  LCD_RD = 0; // Выставляем сигнал чтения

  delay_us(5);  // Ждем установки данных на шине

  // Это пригодится, если драйвер использовать под STM32 с большой частотой шины

  value = PF_IDR; // Читаем старший байт

  value <<= 8;    // Двигаем его влево на 8 разрядов

  value += PB_IDR; // Читаем младший байт

  LCD_RD = 1;   // Сбрасываем линию RD

  PB_DDR = 0xFF;  // Переводим шину данных на вывод

  PF_DDR = 0xFF;

  return value;

}

 

// Процедура записи данных в регистр

// Очень полезна при инициализации

void LCD_WriteReg(unsigned int LCD_Reg, unsigned int LCD_RegValue){

  LCD_CS = 0; // Активируем Chip Select

  LCD_WriteIndex(LCD_Reg);  // Пишем адрес регистра

  LCD_WriteData(LCD_RegValue);  // Пишем в него данные

  LCD_CS = 1; // Деактивируем Chip Select

}

 

// Процедура чтения из регистра или ОЗУ

unsigned int LCD_ReadReg(unsigned int LCD_Reg){

  unsigned int reg_val;

  LCD_CS = 0; // Активируем Chip Select

  LCD_WriteIndex(LCD_Reg); // Пишем адрес регистра

  reg_val = LCD_ReadData(); // Читаем данные из регистра

  LCD_CS = 1; // Деактивируем Chip Select

  return reg_val;

}

 

// Процедура установки адресных регистров контроллера дисплея

void LCD_SetCursor(unsigned int Xpos, unsigned int Ypos ){

  extern unsigned int X;  // Эти две переменные у меня глобальные

  extern unsigned char Y; // от них ведется отсчет для следующего вывода букв

  X = Xpos; // Обновляем их новыми значениями

  Y = Ypos;

  LCD_WriteReg(0x004e, Ypos );  // Записываем новые значения в счетчики строк

  LCD_WriteReg(0x004f, Xpos );  // и столбцов

}

 

// Самая вкусная часть - инициализация дисплея

void LCD_Initializtion(void){

  delay_ms(100);  // Выжидаем некоторое время (может потребоваться на больших частотах)

  LCD_RES = 1;    // Деактивируем аппаратный сброс, который был активирован при настройке портов МК

  // Теперь записываем данные для настройки контроллера дисплея

  // Эти параметры я брал в интернете. Сначала происходит настрока внутреннего преобразователя

  // для питания стекляшки. Эти параметры я менять не советую...

  LCD_WriteReg(0x0028,0x0006);  // VCOM OTP

  LCD_WriteReg(0x0000,0x0001);  // Oscillation start

  LCD_WriteReg(0x0003,0xaea4);  // power control 1---line frequency and VHG,VGL voltage

  LCD_WriteReg(0x000c,0x0004);  // power control 2---VCIX2 output voltage

  LCD_WriteReg(0x000d,0x000c);  // power control 3---Vlcd63 voltage

  LCD_WriteReg(0x000e,0x2800);  // power control 4---VCOMA voltage VCOML=VCOMH*0.9475-VCOMA

  LCD_WriteReg(0x001e,0x00b5);  // POWER CONTROL 5---VCOMH voltage

  // Следующие параметры описаны в ДШ на стр. 30-31. Они определяют порядок сканирования строк,

  // порядок вывода цветов и др.

  LCD_WriteReg(0x0001,0x3B3F);  // Driver Output Control

  // Следующую строку также менять не советую

  LCD_WriteReg(0x0002,0x0600);  // LCD Drive AC Control

  // Регистр управления режимом Sleep. Может понадобиться для устройств с батарейным питанием

  // Для справки: Дисплей потребляет от 2,5 до 8 мА в активном режиме

  // и от 70 до 300 мкА в спящем (стр. 63 ДШ)

  LCD_WriteReg(0x0010,0x0000);  // Sleep Mode

  // Режим позиционирования и направления сканирования дисплея.

  // Для данных значений при расположении дисплея в Landscape контроллер справа

  // нижний левый угол будет иметь координаты 0,0

  // Я такие значения применил для вывода изображений из BMP файлов

 

  // Для Portrait положения дисплея строка будет иметь вид LCD_WriteReg(0x0011,0x6830);

  // Более подробно по данной установке можно прочитать на стр. 43-46 ДШ

  LCD_WriteReg(0x0011,0x6838);  // Entry Mode

  // Не нашел этих параметров в ДШ, но переписывать не стал...

  LCD_WriteReg(0x0005,0x0000);  // ???

  LCD_WriteReg(0x0006,0x0000);  // ???

  LCD_WriteReg(0x0016,0xef1c);  // ???

  // Следующие настройки можно посмотреть на стр. 39 ДШ

  LCD_WriteReg(0x0007,0x0033);  // Display control 1

    /* when GON=1 and DTE=0,all gate outputs become VGL */

    /* when GON=1 and DTE=0,all gate outputs become VGH */

    /* non-selected gate wires become VGL */

  // Далее расположены настройки размера видимой области дисплея. Их можно менять

  // по ходу работы при необходимости вывода в определенную область экрана

  LCD_WriteReg(0x000b,0x0000);  // Frame Cycle Control

  LCD_WriteReg(0x000f,0x0000);  // Gate Scan Start Position

  LCD_WriteReg(0x0041,0x0000);  // Vertical Scroll Control 1

  LCD_WriteReg(0x0042,0x0000);  // Vertical Scroll Control 2

  LCD_WriteReg(0x0048,0x0000);  // First Window Start

  LCD_WriteReg(0x0049,0x013f);  // First Window End

  LCD_WriteReg(0x004a,0x0000);  // Second Window Start

  LCD_WriteReg(0x004b,0x0000);  // Second Window End

  LCD_WriteReg(0x0044,0xef00);  // Horizontal RAM start and end address

  LCD_WriteReg(0x0045,0x0000);  // Vertical RAM start address

  LCD_WriteReg(0x0046,0x013f);  // Vertical RAM end address

  // Счетчики строк и столбцов. Я их меняю функцией LCD_SetCursor

  LCD_WriteReg(0x004e,0x0000);  // Set GDDRAM X address counter

  LCD_WriteReg(0x004f,0x0000);  // Set GDDRAM Y address counter

  // Управление гаммой цветов. Для предотвращения искажения не рекомендую менять их

  LCD_WriteReg(0x0030,0x0707);

  LCD_WriteReg(0x0031,0x0202);

  LCD_WriteReg(0x0032,0x0204);

  LCD_WriteReg(0x0033,0x0502);

  LCD_WriteReg(0x0034,0x0507);

  LCD_WriteReg(0x0035,0x0204);

  LCD_WriteReg(0x0036,0x0204);

  LCD_WriteReg(0x0037,0x0502);

  LCD_WriteReg(0x003a,0x0302);

  LCD_WriteReg(0x003b,0x0302);

  LCD_WriteReg(0x0023,0x0000);

  LCD_WriteReg(0x0024,0x0000);

  LCD_WriteReg(0x0025,0x8000);

  LCD_WriteReg(0x0026,0x7000);

  LCD_WriteReg(0x0020,0xb0eb);

  LCD_WriteReg(0x0027,0x007c);

  // После выполнения этой процедуры дисплей должен включиться и на экране появится

  // мусор в виде случайным образом засвеченных точек

}

 

void LCD_Pset(unsigned int color){

 

 

}

 

// Функция очистки дисплея заливает весь экран цветом, указанным в аргументе Color

void LCD_Clear(unsigned int Color){

  unsigned long index=0;

  LCD_SetCursor(0,0); // Устанавливаем курсор в начало

  LCD_CS = 0;         // Здесь запись организована "атомарно" для ускорения процедуры

  LCD_WriteIndex(0x0022); // Запись этого адреса в регистр индекса означает, что

                          // сейчас будут выводиться данные в экранное ОЗУ

                          // Как себя будут вести счетчики строк и столбцов определяется

                          // регистром с адресом 0x0011

  for(index=0;index < 0x12C00;index++){ // цикл с количеством итераций 320*240

    LCD_WriteData(Color); // ставим точки заданного цвета

  }

  LCD_CS = 1;         // Отцепляемся от дисплея

}

 

// Одна из сложнейших функций - вывод буквы в текущую позицию дисплея

void LCD_Putchar(unsigned char chr){  // Аргумент - код буквы

  unsigned char i, a, tmp;

  unsigned int addr;

  extern unsigned int paper, ink; // Глобальные переменные - цвет фона и буквы

  extern unsigned int X;          // Глобальные переменные позиции буквы

  extern unsigned char Y;

  switch(chr){  // Так я организовал переход на новую строку

    case 10:

      Y -= 9;

    break;

    case 13:    // И "возврат каретки"

      X = 3;

    break;

    default:

      addr = chr << 3;

      tmp = Y;  // сохраняем позицию для возврата при отображении новой строки точек

      for(i=0;i<8;i++){     //Счетчик строки знакоместа

        LCD_WriteReg(0x004e,Y); // Установка координаты Y

        LCD_CS = 0;         // Выводим строку точек

        LCD_WriteIndex(0x0022);

        for(a=0;a<8;a++){   //Счетчик столбцов знакоместа

          if(NewFont8x8[addr+a]&(0x80>>i)){ // Если в знакоместе точка = 1

            LCD_WriteData(ink);     // Выводим цвет ink

          }else{

            LCD_WriteData(paper);   // Иначе цвет фона

          }

        }

        LCD_CS = 1;

        Y++;  // Переходим на новую строку знакоместа

      }

      Y = tmp;  // Восстанавливаем значение буквы по вертикали

      // Ниже расположено вычисление ширины буквы для более плотного расположения текста на экране

      i = 3;   

      for(a=7;a!=0;a--){

        if(NewFont8x8[addr+a] != 0x00){

          i = a + 2;

          break;

        }

      }

      // Переходим на новую строку если достигли правого края экрана

      X += i;

      if(X > 310){

        Y -= 9;

        X = 3;

      }

    break;

  }

  LCD_SetCursor(X, Y); // Координаты следует сохранить для вывода последующего символа

}

 

// Вывод строки на экран. В качестве аргумента - указатель на строку

void LCD_PutString(char* str){//

  unsigned int i=0;

  while(str[i]){  // Пока не встретим терминатора...

    LCD_Putchar(str[i]);

    i++;

  }

}

 

// Это я написал ввиду наличия строковых констант

void putString(const char* str){//

  unsigned int i=0;

  while(str[i]){

    LCD_Putchar(str[i]);

    i++;

  }

}
admin
Администратор
 
Сообщений: 56
Зарегистрирован: 27 ноя 2016, 18:21

Вернуться в Для продвинутых. Обсуждение проектов.

Кто сейчас на форуме

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1

cron
/