Графический дисплей LCD 12864 (128x64 пикселя) на ST7920
-
aleksandr-zh
- Сверлит текстолит когтями
- Сообщения: 1278
- Зарегистрирован: Пн июн 18, 2007 21:51:20
Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920
хм
я иной алгоритм надумал,как получу ЖКИ - опробую
мне надо крупные шрифты, от 16 точек
я иной алгоритм надумал,как получу ЖКИ - опробую
мне надо крупные шрифты, от 16 точек
Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920
aleksandr-zh писал(а):хм
я иной алгоритм надумал,как получу ЖКИ - опробую
мне надо крупные шрифты, от 16 точек
Если нужно выводить шрифт с шириной кратной 8-ми тачкам (8,16,24,32), то буфер не нужен... можно выводить прям в дисплей...
Но если будут шрифты с шириной не кратной 8-ми, то придется через буфер.....
Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920
Вадиматоричик писал(а):Рад, что этот дисплей приобрел такую популярность. Есть даже статья на хабре http://habrahabr.ru/post/213459/. Попытался по ней написать нормальную библиотеку для работы по SPI. Но столкнулся с проблемой. Если подать "0" (-) на SPB (Для разрешения приема данных) вся цепь замыкается. У меня питается от программатора, так что гаснет все. Программатор в том числе. У кого-нибудь еще такое было? И еще. На дисплее по ссылке GND и VCC, по сравнению с мои дисплеем, на разных местах. Я об этом узнал уже после того, как подключил и цепь замкнулась. Даже и не подумал, что пины могут отличаться по назначению. Видимо, не судьба с SPI мне поработать... Спасибо за примеры. Буду стараться написать еще более компактный код
У меня такая-же беда. Купил дисплеи в Китае специально под Serial режим...
Удалось победить?
Все, разобрался. На плате уже установлена перемычка...
- Вложения
-
- 2014-06-18 06.52.33 (640x480).jpg
- (137.4 КБ) 2282 скачивания
-
aleksandr-zh
- Сверлит текстолит когтями
- Сообщения: 1278
- Зарегистрирован: Пн июн 18, 2007 21:51:20
Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920
shads писал(а):aleksandr-zh писал(а):хм
я иной алгоритм надумал,как получу ЖКИ - опробую
мне надо крупные шрифты, от 16 точек
Если нужно выводить шрифт с шириной кратной 8-ми тачкам (8,16,24,32), то буфер не нужен... можно выводить прям в дисплей...
Но если будут шрифты с шириной не кратной 8-ми, то придется через буфер.....
сел делать, ан фиг вам, товарищи
во-первых, идиотская адресация. Победил: сделал по Х 0-7 блоков, и по Y 0-7 - строк
дело в том, что выгрузить просто 8*8 в любое место не получится простыми способами. По горизонтали запись ведётся * + 8 бит. Т.е., можно вывести только в левую часть блока. Или два символа сразу. А вывести по-простому в правую -никак
Это пол беды, в памяти небольшой буфер + анализ соседнего символа и сразу два выводить. Сносно
но меня в тупик поставило вот что:
есть в памяти программ массив с данными шрифтов. Как обратиться к началу нужного символа? как адресоваться туда?
Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920
Создается указатель, указывающий на начало массива, потом к нему нужно прибавить (порядковый номер нужного символа в массиве, умноженный на значение размерности символов в массиве), вот вам и начало нужного символа...aleksandr-zh писал(а):есть в памяти программ массив с данными шрифтов. Как обратиться к началу нужного символа? как адресоваться туда?
-
aleksandr-zh
- Сверлит текстолит когтями
- Сообщения: 1278
- Зарегистрирован: Пн июн 18, 2007 21:51:20
Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920
shads писал(а):Создается указатель, указывающий на начало массива, потом к нему нужно прибавить (порядковый номер нужного символа в массиве, умноженный на значение размерности символов в массиве), вот вам и начало нужного символа...aleksandr-zh писал(а):есть в памяти программ массив с данными шрифтов. Как обратиться к началу нужного символа? как адресоваться туда?
Уже давно сделал ))
И шрифты, и эффект bold...
Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920
Ждем фоток, с примерчиками сообщений на дисплееaleksandr-zh писал(а):Уже давно сделал ))
-
aleksandr-zh
- Сверлит текстолит когтями
- Сообщения: 1278
- Зарегистрирован: Пн июн 18, 2007 21:51:20
Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920
вот:
шрифты сам рисовал, в свободных сделал пару десятков ходовых символов: батарея заряжена, половина, разряжена, всякие пиктограмки: вход\выход в меню, стрелочки,....
на одной из фотографий пиктограмка вилки
мол, питание от сети 220в
можно всё сделать, была бы фантазия!
эффект Bold сделан программно из обычного шрифта: смещаю на 1 позицию всю строку




шрифты сам рисовал, в свободных сделал пару десятков ходовых символов: батарея заряжена, половина, разряжена, всякие пиктограмки: вход\выход в меню, стрелочки,....
на одной из фотографий пиктограмка вилки
можно всё сделать, была бы фантазия!
эффект Bold сделан программно из обычного шрифта: смещаю на 1 позицию всю строку




Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920
На верхней картинке - где коровка - текст явно вместе с картинкой выводится, графически? Т.к. видно, что он не по знакоместам расположен...
-
aleksandr-zh
- Сверлит текстолит когтями
- Сообщения: 1278
- Зарегистрирован: Пн июн 18, 2007 21:51:20
Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920
shads писал(а):На верхней картинке - где коровка - текст явно вместе с картинкой выводится, графически? Т.к. видно, что он не по знакоместам расположен...
да-да!
там картинка, просто для проверки скорости выгрузки
ЖКИ подключен по SPI, картинка хранится во внешней EEPROM (24lc64 - что было под рукой)
Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920
За какое время картинка выводится по SPI? Не смотрели?aleksandr-zh писал(а):ЖКИ подключен по SPI
10 раз\сек получится обновлять весь экран?
-
aleksandr-zh
- Сверлит текстолит когтями
- Сообщения: 1278
- Зарегистрирован: Пн июн 18, 2007 21:51:20
Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920
у меня тест плохой: я же беру из внешней EEPROM - очень медленно! секунда ГРУБО
-
Вадиматоричик
- Грызет канифоль
- Сообщения: 299
- Зарегистрирован: Пн май 16, 2011 10:54:32
- Откуда: Красноярск
Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920
Здравствуйте все
. Ну вот, я снова вернулся в эту тему. Мне нужно было время, чтобы немного в себе разобраться, переосмыслить многие вещи, подтянуть свои знания в СИ и разобраться с STM8 и 32.
Предыстория:
Хотелось что-нибудь с пользовательским интерфейсом. Хоть в STM32 и есть LTDC (Модуль управления RGB дисплеями без контроллера) с DMA2D (встроенный графический ускоритель с возможностью самостоятельно рисовать различные фигуры на экране) + на моей отладочной плате еще был экран 240*320, но слишком он уж сложен в освоении да и для домашних поделок это перебор. + не для каждого проекта захочется покупать контроллер за 500 руб. И тут я начал смотреть в сторону STM8. Контроллеры с виду очень понравились, а как только начал с ними работать - так на всегда для себя решил отказаться от AVR. Хоть STM8 чуть-чуть и уступают в производительности, но зато отлаживать программы на них - одно удовольствие, но да ладно. Как вы уже поняли, я начал разбираться с нашим LCD заново.
Т.к. в интернете я не нашел ни одного упоминания подключения нашего LCD по SPI к STM8, то я решил написать библиотеку сам. И, забыв про все грабли, начал писать. В конце этого сообщения есть файл проекта с моей библиотекой и примером. Библиотека сейчас активно дорабатывается и в будущем будет прикреплена к какой-нибудь RTOS.
Связь STM8 и LCD по SPI:
Далее я начал читать эту статью, из которой я подчеркнул подключение дисплея и принцип передачи. Но возникли определенные проблемы:
1. В статье написано:
Как оказалось, нужно передать сначала 5 единиц подряд, а не 4.
2.
Непонятно было, передавать со старшего к младшему или от младшего к старшему. Оказалось, что нужно передавать именно со старшего к младшему: 7 бит, 6 бит, 5 бит, 4-й, четыре нуля, 3-й, 2-й, 1-й, 0-й, снова 4 нуля.
На этом проблемы с подключением закончились.
Библиотечная реализация соединения (низкий уровень).
За отправку байтов по SPI в LCD отвечает функция SPI_Out. Их тоже 2. Закомментированная так же программная, отправляет с 7-го бита по 0-й, как и аппаратная.
За отправку байта данных или команды отвечает функция LCD_OUT. Она принимает 2 параметра:
1. Байт данных.
2. Комманда или данные. Есть в defin-ах.
Пример использования:
Использование стандартного шрифта.
Для отправки строки используется функция LCD_OutString_std. Функция выводит входную строку до символа с кодом 0x00. Пример использования.
Вот как выглядит этот код в жизни (программный SPI).

Сразу скажу, над этой функцией долго не работал, т.к. в своей практике использовать не буду.
Использование собственных символов 8x8.
Для начала нужно инициализировать дисплей в режиме SPI. Делается это функцией без параметров LCD_Graf_Init();. Далее появится мусор на экране. Его можно очистить функцией LCD_Graf_Clear();.
Вывод символов (которые лежат скачанные в отдельном файле) производится так, сначала функцией LCD_Graf_Out_char (символ, положение по оси x, положение по оси y) символ закачивается в буфер в нужном месте, далее функцией OUT_Graf_BUFFER на экран выводится весь буфер на экран. Если нужно вывести строку, то достаточно лишь вызвать функцию OUT_Graf_String ("строка"+0x00, координата 1-го символа по оси x, координата по оси y), после так же вывести буфер на экран. Если строка не поместилась в строку, то она автоматически продолжается с начала новой строки. Если строка не влезла в последнюю строку, то она продолжается с начала. Применяется кодировка размером 8x8, с русскими символами. Пример вывода символа и строки.

Можно и не дописывать 0x00 в конце, но я все таки делаю это.
Работа с графикой: (Рисование линий).
1. Horiz (горизонтальная) или Vert (вертикальная) линия.
Далее так. Если линия горизонтальная, то.
2. Отступ слева в пикселях (0...128).
3. Длинна пикселей вправо (включая 1-й пиксель).
4. Положение по оси Y (константа), так же от 0 до 63.
Если линия вертикальная, то:
2. Отступ пикселей сверху (0...63).
3. Длинна вниз (0..64).
4. Отступ слева по оси X (0..128).
Вот пример кода, рисующего прямоугольник с отступом в 1 пиксель от каждой грани экрана и надпись внутри него + символ.
Выглядит это так:

Работа с графикой: (Рисование прямоугольников).
Все, что функции пишут в буфер - происходит наложением. Так что если буква занимает ни все отведенное ей пространство 8x8, то там спокойно можно провести линию.
Вот собственно и библиотека. Код написан на C, под IAR для контроллера stm8s105c4, но код не имеет ассемблерных вставок, так что перенос будет легкий
Глюки библиотеки:
Предыстория:
Спойлер
Изучая новое семейство STM32 я понял, что такая мощность мне ни к чему, да и питаются они только лишь от 3.3 вольта, что влечет за собой применение устройств согласования уровней при подключении многих модулей, а это дополнительные расходы, что в быту бывает критично.Хотелось что-нибудь с пользовательским интерфейсом. Хоть в STM32 и есть LTDC (Модуль управления RGB дисплеями без контроллера) с DMA2D (встроенный графический ускоритель с возможностью самостоятельно рисовать различные фигуры на экране) + на моей отладочной плате еще был экран 240*320, но слишком он уж сложен в освоении да и для домашних поделок это перебор. + не для каждого проекта захочется покупать контроллер за 500 руб. И тут я начал смотреть в сторону STM8. Контроллеры с виду очень понравились, а как только начал с ними работать - так на всегда для себя решил отказаться от AVR. Хоть STM8 чуть-чуть и уступают в производительности, но зато отлаживать программы на них - одно удовольствие, но да ладно. Как вы уже поняли, я начал разбираться с нашим LCD заново.
Т.к. в интернете я не нашел ни одного упоминания подключения нашего LCD по SPI к STM8, то я решил написать библиотеку сам. И, забыв про все грабли, начал писать. В конце этого сообщения есть файл проекта с моей библиотекой и примером. Библиотека сейчас активно дорабатывается и в будущем будет прикреплена к какой-нибудь RTOS.
Связь STM8 и LCD по SPI:
Спойлер
Т.к. у меня нет логического анализатора и я никогда ранее не работал с этим дисплеем по SPI, то реализовать интерфейс я решил "дрыганьем ножек" с большой задержкой и подключенными светодиодами к пинам, чтобы проследить, что все биты доходят нормально (После успешного соединения перевел на аппаратный SPI. В библиотеке есть обе реализации). Как я писал ниже - мне досталась старая версия дисплея, и чтобы перевести его из параллельного в SPI - мне пришлось перепаять резистор (перемычку, как оказалось). Иначе происходило замыкание при правильном подключении.Далее я начал читать эту статью, из которой я подчеркнул подключение дисплея и принцип передачи. Но возникли определенные проблемы:
1. В статье написано:
В SPI режиме передача одной команды или 1 байта данных происходит при передачи 24 бит
Протокол передачи данных таков:
Устанавливаем высокий уровень CS
Передаем 4 единицы подряд
Передаем 1 бит RW – чтения или запись
Передаем 1 бит RS – Команда или данные
Передаем 0
Передаем 4 бита старшей половины байта данных
Передаем 4 нуля
Передаем 4 бита младшей половины байта данных
Передаем 4 нуля подряд
Устанавливаем низкий уровень CS
Как оказалось, нужно передать сначала 5 единиц подряд, а не 4.
2.
Передаем 4 бита старшей половины байта данных
Непонятно было, передавать со старшего к младшему или от младшего к старшему. Оказалось, что нужно передавать именно со старшего к младшему: 7 бит, 6 бит, 5 бит, 4-й, четыре нуля, 3-й, 2-й, 1-й, 0-й, снова 4 нуля.
На этом проблемы с подключением закончились.
Библиотечная реализация соединения (низкий уровень).
Спойлер
За инициализацию SPI отвечает функция SPI_Init();. Причем их в библиотеке 2. Та, которая закомментирована - программная (медленная), 2-я аппаратная с делителем частоты f\8 (при частоте встроенного генератора в 16 мгц), использует 2 линии (выход и тактирование, вход отключен для экономии выводов (Это, несомненно, + STM8)) + CS так же "ногодрыг" (изменяется в ручную). При такой аппаратной конфигурации экран полностью обновляется в режиме картинки примерно за пол секунды.За отправку байтов по SPI в LCD отвечает функция SPI_Out. Их тоже 2. Закомментированная так же программная, отправляет с 7-го бита по 0-й, как и аппаратная.
За отправку байта данных или команды отвечает функция LCD_OUT. Она принимает 2 параметра:
1. Байт данных.
2. Комманда или данные. Есть в defin-ах.
Код: Выделить всё
#define Command 0 //Отправка комманды или данных.
#define Data 1
Пример использования:
Код: Выделить всё
LCD_OUT(0x30, Command); //8 бит, стандартный набор комманд.
Использование стандартного шрифта.
Спойлер
Для начала LCD нужно инициализировать в текстовом режиме. Для этого служит библиотека LCD_TextStandart_Init();. Функция не требует входных параметров и вызывается перед использованием дисплея. Последовательность была взята из статьи выше.Для отправки строки используется функция LCD_OutString_std. Функция выводит входную строку до символа с кодом 0x00. Пример использования.
Код: Выделить всё
int main( void )
{
Led_init();
SPI_Init();
LCD_TextStandart_Init();
LCD_OutString_std("Loooool)))"+0x00);
while (1)
{
}
}
Вот как выглядит этот код в жизни (программный SPI).
Сразу скажу, над этой функцией долго не работал, т.к. в своей практике использовать не буду.
Использование собственных символов 8x8.
Спойлер
В моем МК есть аж 2 кб ОЗУ, так что я решил сделать в памяти МК буфер для всего экрана, а после просто обновлять его. По-началу хотел делать без буфера, но адресация меня убила и я решил, что так будет куда проще (Да и в будущем все равно без буфера не обойтись).Для начала нужно инициализировать дисплей в режиме SPI. Делается это функцией без параметров LCD_Graf_Init();. Далее появится мусор на экране. Его можно очистить функцией LCD_Graf_Clear();.
Вывод символов (которые лежат скачанные в отдельном файле) производится так, сначала функцией LCD_Graf_Out_char (символ, положение по оси x, положение по оси y) символ закачивается в буфер в нужном месте, далее функцией OUT_Graf_BUFFER на экран выводится весь буфер на экран. Если нужно вывести строку, то достаточно лишь вызвать функцию OUT_Graf_String ("строка"+0x00, координата 1-го символа по оси x, координата по оси y), после так же вывести буфер на экран. Если строка не поместилась в строку, то она автоматически продолжается с начала новой строки. Если строка не влезла в последнюю строку, то она продолжается с начала. Применяется кодировка размером 8x8, с русскими символами. Пример вывода символа и строки.
Код: Выделить всё
int main( void )
{
Led_init();
SPI_Init();
LCD_Graf_Init();
LCD_Graf_Clear();
OUT_Graf_String("Èíîãäà ÿ äóìàþ äîëãî("+0x00, 0, 4);
LCD_Graf_Out_char ('I', 2, 2);
OUT_Graf_BUFFER ();
Led_ON;
while (1)
{
}
}
Можно и не дописывать 0x00 в конце, но я все таки делаю это.
Работа с графикой: (Рисование линий).
Спойлер
Я решил, что в будущем использую этот дисплей в связке с ОС реального времени, для чего мне нужен будет интерфейс пользователя. А для этого нужно уметь рисовать его. Решил начать с линий. Т.к. мне нужны будут лишь горизонтальные и вертикальные линии произвольной длинны, то я решил написать свой алгоритм (на что убил 2 дня). В библиотеке есть функция OUT_Graf_Line, она принимает 4 параметра.1. Horiz (горизонтальная) или Vert (вертикальная) линия.
Далее так. Если линия горизонтальная, то.
2. Отступ слева в пикселях (0...128).
3. Длинна пикселей вправо (включая 1-й пиксель).
4. Положение по оси Y (константа), так же от 0 до 63.
Если линия вертикальная, то:
2. Отступ пикселей сверху (0...63).
3. Длинна вниз (0..64).
4. Отступ слева по оси X (0..128).
Вот пример кода, рисующего прямоугольник с отступом в 1 пиксель от каждой грани экрана и надпись внутри него + символ.
Код: Выделить всё
int main( void )
{
Led_init();
SPI_Init();
LCD_Graf_Init();
OUT_Graf_String("Интересная", 1, 3);
OUT_Graf_String("надпись", 5, 4);
LCD_Graf_Out_char (')', 12, 5);
OUT_Graf_Line(Vert, 1, 62, 1);
OUT_Graf_Line(Vert, 1, 62, 126);
OUT_Graf_Line(Horiz, 1, 126, 1);
OUT_Graf_Line(Horiz, 1, 126, 62);
OUT_Graf_BUFFER ();
Led_ON;
while (1)
{
}
}
Выглядит это так:
Работа с графикой: (Рисование прямоугольников).
Спойлер
Для работы с прямоугольниками есть функция OUT_Graf_Prm, она имеет 4 параметра: координаты левого верхнего угла (х, у) и координаты правого нижнего угла (х, у). Значения для Х [0..128], Y [0..64]. Пример рисовки такого же прямоугольника, как на рисунке в примерах рисования линий.Код: Выделить всё
int main( void )
{
Led_init();
SPI_Init();
LCD_Graf_Init();
OUT_Graf_String("Èíòåðåñíàÿ", 1, 3);
OUT_Graf_String("íàäïèñü", 5, 4);
LCD_Graf_Out_char (')', 12, 5);
OUT_Graf_Prm (1, 1, 127, 63);
OUT_Graf_BUFFER ();
Led_ON;
while (1)
{
}
}
Все, что функции пишут в буфер - происходит наложением. Так что если буква занимает ни все отведенное ей пространство 8x8, то там спокойно можно провести линию.
Вот собственно и библиотека. Код написан на C, под IAR для контроллера stm8s105c4, но код не имеет ассемблерных вставок, так что перенос будет легкий
Глюки библиотеки:
Спойлер
1. При использовании стандартных символов, передача возможна лишь с помощью программной инициализации SPI. Скорее всего я просто не выдержал задержки при работе с контроллером символов. Т.к. я не использую стандартные символы вообще - мне не критично.Все можно сделать, было бы желание!
-
Вадиматоричик
- Грызет канифоль
- Сообщения: 299
- Зарегистрирован: Пн май 16, 2011 10:54:32
- Откуда: Красноярск
Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920
Немного поработал над библиотекой и добавил несколько новых функций:
2. Библиотека вынесена в отдельный файл (LCD12864.h и LCD12864.c). В 1-м файле (.h) вынесены заголовки всех функций с их небольшим описанием + необходимые #define, а во 2-м сами функции (С кучей комментариев). Для подключения к проекту нужно подключить оба файла к проекту. У меня они подключены так.
3. Работы с SPI так же в отдельных файлах SPI.h и SPI.c. Так же в .h описания и заголовки - во 2-м сами функции. Так же осталась аппаратная и программная реализация. По умолчанию раскомментирована аппаратная (железная). Их так же необходимо подключить к проекту (Раньше файлов библиотек экрана! Иначе не будет компилироваться.)
4. Добавлена функция копирования изображения любого размера (не больше размера экрана) из програмной памяти в ОЗУ, с возможностью выбора координат копирования и смещения рисунка по осям X и Y по пикселям (Это далось сложнее всего). Это делается с помощью функции void OUT_Graf_PasteJmeg (char x1, char y1, const char mes_name[], const char mes_set[]). Поясню как с ней работать. Параметр №
1. Смещение по оси Х.
2. Смещение по оси Y.
3. Имя массива картинки.
4. Имя массива информации о картинке.
Пример работы с библиотекой.
Допустим нам нужно нарисовать "рыбку" размером 8 на 16 пикселей, для этого:
1. Подготовка картинки:
2. В графе image нажимаем на знак папки и добавляем свою картинку. Кстати, картинка обязательна по оси X должна быть кратна 8!. Так что если она занимает, к примеру, 5 символов, то нужно оставить до 8 пустое место (т.к. изображение накладывается, а не замещает, ничего страшного не произойдет).
3. В строке Name пишем на английском имя нашего массива.
4. В правом окне переворачиваем изображение на 90 градусов (Это какой-то прикол программы, иначе получается 2 рядом стоящих сплющенных изображения).
5. В пункте bit\point выбираем 1pbb. Все 3 галочки (Перевороты X, Y и RLE) должны быть сняты.
6. Далее нажимаем в левом окне на generate и получаем код.
В верхнем окне получится что-то типа:
Отсюда нам нужно скопировать сам код картинки, и его параметры, но чуть изменив.
Здесь меняем uint на char (В IAR нет uint, да и нам лучше использовать char, с ним проблем меньше).
Здесь нужно заменить почти все...
Меняем на char [2]
А из всех строк оставляем только первые 2. Ширину и высоту.
Должно получиться что-то вроде:
Советую вынести это в отдельный файл. Я, например, создал файл Resurs.h, и там храню изображения и информацию о них. Только не забудьте в начале проекта подключить его.
2. Настроить функцию.
Вот пример моего кода.
Вот так выглядит мой пример в жизни:
А вот картинка рыбки, если кто захочет свериться.

Вот проект примера работы библиотеки:
А вот и сама библиотека
Буду вводить уже им версии. Т.к. слишком уж большой функционал планируется.
Так вот, это версия 1.1
А вот и видио работы кода.
Спойлер
1. Теперь можно очистить буфер (ОЗУ) LCD. За это отвечает функция void OUT_Graf_BUFFER (void);, не требующая параметров.2. Библиотека вынесена в отдельный файл (LCD12864.h и LCD12864.c). В 1-м файле (.h) вынесены заголовки всех функций с их небольшим описанием + необходимые #define, а во 2-м сами функции (С кучей комментариев). Для подключения к проекту нужно подключить оба файла к проекту. У меня они подключены так.
Код: Выделить всё
#include "inc\LCD12864.h" //Библиотека работы с LCD.
#include "inc\LCD12864.c"
3. Работы с SPI так же в отдельных файлах SPI.h и SPI.c. Так же в .h описания и заголовки - во 2-м сами функции. Так же осталась аппаратная и программная реализация. По умолчанию раскомментирована аппаратная (железная). Их так же необходимо подключить к проекту (Раньше файлов библиотек экрана! Иначе не будет компилироваться.)
4. Добавлена функция копирования изображения любого размера (не больше размера экрана) из програмной памяти в ОЗУ, с возможностью выбора координат копирования и смещения рисунка по осям X и Y по пикселям (Это далось сложнее всего). Это делается с помощью функции void OUT_Graf_PasteJmeg (char x1, char y1, const char mes_name[], const char mes_set[]). Поясню как с ней работать. Параметр №
1. Смещение по оси Х.
2. Смещение по оси Y.
3. Имя массива картинки.
4. Имя массива информации о картинке.
Пример работы с библиотекой.
Допустим нам нужно нарисовать "рыбку" размером 8 на 16 пикселей, для этого:
1. Подготовка картинки:
Спойлер
1. Открываем программу Bitmap2Code, ссылка на которую есть в 1-м посте темы.2. В графе image нажимаем на знак папки и добавляем свою картинку. Кстати, картинка обязательна по оси X должна быть кратна 8!. Так что если она занимает, к примеру, 5 символов, то нужно оставить до 8 пустое место (т.к. изображение накладывается, а не замещает, ничего страшного не произойдет).
3. В строке Name пишем на английском имя нашего массива.
4. В правом окне переворачиваем изображение на 90 градусов (Это какой-то прикол программы, иначе получается 2 рядом стоящих сплющенных изображения).
5. В пункте bit\point выбираем 1pbb. Все 3 галочки (Перевороты X, Y и RLE) должны быть сняты.
6. Далее нажимаем в левом окне на generate и получаем код.
В верхнем окне получится что-то типа:
Код: Выделить всё
//
// Bitmap data for Kr
//
//Kr array, size 16 bytes
const uint Kr[16] = {
0x40, 0x3c, 0xa0, 0x42, 0x10, 0x81, 0x1f, 0x99, 0x1f, 0x99,
0x10, 0x81, 0xa0, 0x42, 0x40, 0x3c, };
// Bitmap information for Kr
const BITMAP_INFO KrInfo =
{
7, // Picture Width - 1
15, // Picture Height - 1
0, // RLE Copressed flag, if yes value = 1
16, // Bitmap array size
Kr, // Bitmap point array
};
Отсюда нам нужно скопировать сам код картинки, и его параметры, но чуть изменив.
Код: Выделить всё
const uint Kr[16] = {
0x40, 0x3c, 0xa0, 0x42, 0x10, 0x81, 0x1f, 0x99, 0x1f, 0x99,
0x10, 0x81, 0xa0, 0x42, 0x40, 0x3c, };
Здесь меняем uint на char (В IAR нет uint, да и нам лучше использовать char, с ним проблем меньше).
Код: Выделить всё
const BITMAP_INFO KrInfo =
{
7, // Picture Width - 1
15, // Picture Height - 1
0, // RLE Copressed flag, if yes value = 1
16, // Bitmap array size
Kr, // Bitmap point array
};
Здесь нужно заменить почти все...
Код: Выделить всё
BITMAP_INFO KrInfoМеняем на char [2]
А из всех строк оставляем только первые 2. Ширину и высоту.
Должно получиться что-то вроде:
Код: Выделить всё
//Kr array, size 8 byte
const char Kffr[16] = {
0x40, 0x3c, 0xa0, 0x42, 0x10, 0x81, 0x1f, 0x99, 0x1f, 0x99,
0x10, 0x81, 0xa0, 0x42, 0x40, 0x3c, };
// Bitmap information for Kr
const char KrffInfo [] =
{
7, // Pictur высота - 1
15, // Picture ширина - 1
};
Советую вынести это в отдельный файл. Я, например, создал файл Resurs.h, и там храню изображения и информацию о них. Только не забудьте в начале проекта подключить его.
2. Настроить функцию.
Спойлер
Допустим нам захотелось, чтобы наша рыбка плавала по всему экрану, для этого делаем 2 цикла (в 1-м рыбка перемещается по оси у, а во 2-м по х). Таким образом рыбка будет плыть слева направо, сверху вниз, от и до строки.Вот пример моего кода.
Код: Выделить всё
int main(void)
{
Led_init();
SPI_Init();
LCD_Graf_Init();
while (1)
{
for (char DvY = 0; DvY < (64-8); DvY=DvY+8) //По оси У. Каждый раз спускаемся на 8 пикселей.
{
for (char DVx = 0; DVx<(128-16); DVx++) //По оси Х. Т.к. картинка 16 пикселей, то делаем отступ, иначе уплывет в никуда.
{
OUT_Graf_PasteJmeg(DVx, DvY, Kffr, KrffInfo); //Смещение по х, по y, имя массива картинки, имя массива параметров.
OUT_Graf_BUFFER (); //Показываем буфер.
Lcd_Clear(); //После каждого наложения чистим буфер.
};
};
};
}
Вот так выглядит мой пример в жизни:
А вот картинка рыбки, если кто захочет свериться.
Вот проект примера работы библиотеки:
А вот и сама библиотека
Буду вводить уже им версии. Т.к. слишком уж большой функционал планируется.
Так вот, это версия 1.1
А вот и видио работы кода.
Спойлер
Все можно сделать, было бы желание!
-
Вадиматоричик
- Грызет канифоль
- Сообщения: 299
- Зарегистрирован: Пн май 16, 2011 10:54:32
- Откуда: Красноярск
Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920
Новая версия: 1.2
Новое: Добавлена возможность рисования закрашенных прямоугольников. За это отвечает функция void OUT_Graf_PrmZK (char X1, char Y1, char X2, char Y2);. Работа с ней ведется точно так же, как и с не закрашенным прямоугольником.
Обновления: теперь свой текст (8x8) может быть 4-х видов.
Данное изменение коснулось функции LCD_Graf_Out_char и OUT_Graf_String. Теперь помимо всех предыдущих входных параметров - нужно еще дописать формат вывода.
Для демонстрации был написан небольшой примерчик. Здесь нижняя часть экрана закрашена прямоугольником и на обеих частях по 4 строчки текста, каждая из которых демонстрирует режим.
Вот фото
Вот библиотека:
А вот пример, описанный выше:
Новое: Добавлена возможность рисования закрашенных прямоугольников. За это отвечает функция void OUT_Graf_PrmZK (char X1, char Y1, char X2, char Y2);. Работа с ней ведется точно так же, как и с не закрашенным прямоугольником.
Обновления: теперь свой текст (8x8) может быть 4-х видов.
Код: Выделить всё
//Режимы вывода символов.
#define FonOFF_InversOFF 0 //Рисует на пустом месте белым по синему, фон не тронут.
#define FonOFF_InversON 1 //Рисует пустым по закрашенному, фон не тронут.
#define FonON_InversOFF 2 //Буква использует весь фон. Рисует по пустому.
#define FonON_InversON 3 //Весь фон, рисует по закрашенному пустотой.
Данное изменение коснулось функции LCD_Graf_Out_char и OUT_Graf_String. Теперь помимо всех предыдущих входных параметров - нужно еще дописать формат вывода.
Для демонстрации был написан небольшой примерчик. Здесь нижняя часть экрана закрашена прямоугольником и на обеих частях по 4 строчки текста, каждая из которых демонстрирует режим.
Код: Выделить всё
int main(void)
{
SPI_Init();
LCD_Graf_Init();
OUT_Graf_PrmZK(0, 32, 128, 64);
OUT_Graf_String ("FonOFF_InversOFF", 0, 0, FonOFF_InversOFF);
OUT_Graf_String ("FonOFF_InversON", 0, 1, FonOFF_InversON);
OUT_Graf_String ("FonON_InversOFF", 0, 2, FonON_InversOFF);
OUT_Graf_String ("FonON_InversON", 0, 3, FonON_InversON);
OUT_Graf_String ("FonOFF_InversOFF", 0, 4, FonOFF_InversOFF);
OUT_Graf_String ("FonOFF_InversON", 0, 5, FonOFF_InversON);
OUT_Graf_String ("FonON_InversOFF", 0, 6, FonON_InversOFF);
OUT_Graf_String ("FonON_InversON", 0, 7, FonON_InversON);
OUT_Graf_BUFFER();
while (1)
{
}
}
Вот фото
Вот библиотека:
А вот пример, описанный выше:
Все можно сделать, было бы желание!
-
Вадиматоричик
- Грызет канифоль
- Сообщения: 299
- Зарегистрирован: Пн май 16, 2011 10:54:32
- Откуда: Красноярск
Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920
А я все не уймусь...
Небольшой рассказ, поясняющий изложенное в посте.
Спойлер
После написания последней выложенной функции я решил подключить сенсорный экран (Touchscreen (тачскрин)), для этого нужно было произвести настройку ADC, а далее - дело за малым. Решив, что сейчас у меня нет времени разбираться с архитектурой - я решил подключить std peripheral library. Хоть я и понимал, что она очень сырая и в ней много глюков - но хоть какой-то каркас кода лучше, чем ничего. И тут начались проблемы.1. К IAR-у библиотека наотрез отказалась подключаться. Решал эту проблему около 2-х дней, но на 3-й день все же получилось чего-то добиться, но при этом понадобилось бы с НУЛЯ переписывать всю СВОЮ библиотеку, что меня взбесило и я решил попробовать другую среду.
2. Попробовав официальную IDE ST Visual Programmer в комплекте с COSMIC-ом, я понял, что Жизнь - боль.
Обе среды мне не нравились с самого начала (Мой идеал (в нем работать просто одно божественное удовольствие) - keil5, но он не поддерживает STM8). Решив, что платформа пока еще развивается, а мне дорога каждая минута - я решил достать свою платку с STM32F429ZI и переписать библиотеку под него. Хоть этот контроллер и слишком огромен для такого экрана (МК спокойно тянет 32-х битные LCD экраны с разрешением 480*800 с кучей различных фич), но перенести программу на МК по-меньше после не составит труда.
Итак, библиотека под STM32. Скажу сразу, пока что это лишь сырой порт, который, убив 2 дня жизни, мне удалось сделать. Функционал такой же, как и в версии 1.2. Но вот в использовании есть небольшие изменения.
Спойлер
1. Настройка SPI и GPIO происходит с помощью StdPeriph (Да, это громоздко, но пока что так. Неизвестно еще, может я на NXP перейду. А функционал нужно расширять).2. По умолчанию передача идет через SPI4 (Их там аж 7!!!), для того, чтобы включить программный SPI - нужно в функции LCD_OUT строку SPI_Out_LCD12864_Ap поменять на SPI_Out_12864_Soft.
Код: Выделить всё
void LCD_OUT (uint8_t Data_LCD, uint8_t Np_LCD)
{
CS_ON(); //Передача начата.
if (Np_LCD == Data) {SPI_Out_LCD12864_Ap(0xFA);} //Передача данных или комманды.
else {SPI_Out_LCD12864_Ap(0xF8);}
SPI_Out_LCD12864_Ap(Data_LCD & 0xF0); //Старшая половина и 4 "0".
SPI_Out_LCD12864_Ap(Data_LCD << 4); //Младшая и 4 "0".
CS_OFF(); //Передача окончина.
}
А вместо SPI_LCD12864_Init_AP_SPI4 использовать для инициализации SPI_LCD12864_Init_Soft.
Скорость выставлена в обоих реализациях SPI методом подбора так, чтобы при кварце в 8 Mhz (без умножителя), изображение приходило без артефактов (Смотрел от большей скорости к меньшей).
От себя: был приятно удивлен, когда включил свой пример "рыбки" при той же скорости кварца, а код работал быстрее. Только потом вспомнил, что у STM8 и STM32 производительность 0.9 против 1.32 (Может чуть напутал в цифрах, лень лезть читать). Приятным плюсом так же оказалась совместимость уровней 3.3 и 5V (Но дисплей питается от 5!). Так что подключение прямое. Кстати о подключении:
Код: Выделить всё
//Используем SPI4.
//PE2 - SPI4_SCK.
//PE3 - CS (ногодрыг).
//PE6 - SPI4_MOSI.
Думаю, если что, изменить настройки нижнего уровня не составит труда.
Вот файл проекта для Keil5. Буду выкладывать целыми проектами, т.к. только на согласование .c и .h файлов у меня ушел день.
Ну вот и фото (На нем можно увидеть светодиоды справа, так, выставляя гигантские задержки я отлаживал SPI). Теперь о скорости вывода. Она ОЧЕНЬ высокая. Если смотреть на мой пример, то видно, что при перемещении, между 2-мя изменениями еще видны "не остывшие" пиксели. Делать скорость еще выше я не вижу смысла, т.к. экран не успевает измениться между новыми порциями данных. Скоростью SPI - доволен.
Фото
P.S. Пока ST не напишет нормальную IDE для STM8 - я буду работать над библиотекой под STM32, а учитывая тенденцию на снижение цен 32-х битных мк, возвращяться к 8 мне уже не придется.
Все можно сделать, было бы желание!
-
Вадиматоричик
- Грызет канифоль
- Сообщения: 299
- Зарегистрирован: Пн май 16, 2011 10:54:32
- Откуда: Красноярск
Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920
Смог соединить наш экран с тачскрином (ранее не работал с ним). Так вышло, что по ширине он на 1-2 пикселя меньше, а в высоту на 3 мм больше с каждой стороны. Так что пришлось писать библиотеку с учетом этого. Из-за SPL конечно опрос происходит ОЧЕНЬ медленно (Всего 2-3 обновления экрана в секунду), но пока что хватит.
Вот фото:

Библиотеку пока не выкладываю, ее ждет огромная оптимизация.
Вот фото:
Библиотеку пока не выкладываю, ее ждет огромная оптимизация.
Все можно сделать, было бы желание!
Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920
Пока ST не напишет нормальную IDE для STM8 - я буду работать над библиотекой под STM32, а учитывая тенденцию на снижение цен 32-х битных мк, возвращяться к 8 мне уже не придется.
ST никогда не напишет... она вообще ни пишет ИДЕ...
А так... ИАР вполне хватает...
И по поводу восьмёрок... S003 для простых поделок очень даже ничего...
"Я не даю готовых решений, я заставляю думать!"(С)
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920
Вашего (нашего) полку прибыло!
Неделю назад тоже получил из китая пару таких дисплеев. Написал свою библиотеку под AVR. Пока только под параллельный 8-битный режим, но добавить 4-битный или последовательный вроде как несложно - протоколы там простые.
Основное моё требование к библиотеке было - совместимость со своей же KS0108-библиотекой. Это, в основном, использование пропорциональных (!) шрифтов с "вертикальными" байтами. Ограничение проистекает из необходимости добавить поддержку дисплея в свой проект спектроанализатора, где подобные шрифты уже используются с дисплеями на базе KS0108 и дисплеем LS020.
Ввиду использования ATmega16 полного экранного буфера (1кБайт) сделать не получалось, так что буфер немного упрощённый - 128 байт (8 строк длинной 128 пикселов), в который легко вписывается нужный шрифт. Буфер вычитывается из экранной памяти (GDRAM) при переходе на очередную "строку" из восьми.
Собственно, вот картинки с текущим результатом:

А исходники под avr-gcc, если кому интересно, можно глянуть на гитхабе.
Неделю назад тоже получил из китая пару таких дисплеев. Написал свою библиотеку под AVR. Пока только под параллельный 8-битный режим, но добавить 4-битный или последовательный вроде как несложно - протоколы там простые.
Основное моё требование к библиотеке было - совместимость со своей же KS0108-библиотекой. Это, в основном, использование пропорциональных (!) шрифтов с "вертикальными" байтами. Ограничение проистекает из необходимости добавить поддержку дисплея в свой проект спектроанализатора, где подобные шрифты уже используются с дисплеями на базе KS0108 и дисплеем LS020.
Ввиду использования ATmega16 полного экранного буфера (1кБайт) сделать не получалось, так что буфер немного упрощённый - 128 байт (8 строк длинной 128 пикселов), в который легко вписывается нужный шрифт. Буфер вычитывается из экранной памяти (GDRAM) при переходе на очередную "строку" из восьми.
Собственно, вот картинки с текущим результатом:
А исходники под avr-gcc, если кому интересно, можно глянуть на гитхабе.
Re: Графический дисплей LCD 12864 (128x64 пикселя) на ST7920
Тоже вариант, но к сожалению так полноценную ИДЕ (с окошками рамочками и прочими приколами) не сварганить...WiseLord писал(а):Ввиду использования ATmega16 полного экранного буфера (1кБайт) сделать не получалось, так что буфер немного упрощённый - 128 байт (8 строк длинной 128 пикселов), в который легко вписывается нужный шрифт. Буфер вычитывается из экранной памяти (GDRAM) при переходе на очередную "строку" из восьми.
Хотя может и вариант, но значительно увеличится нагрузка на контроллер...