Работаем с дисплеем от Nokia 1100 в графическом режиме

Работаем с LCD-экраном Nokia 1100 в графическом режиме

Во второй части поста про подключение дисплея от Nokia 1100 была приведена небольшая библиотека по работе с этим экраном в текстовом режиме. После того, как  я опубликовал пост, возникла небольшая переписка с пользователем под ником -Валера-. Он просил помочь реализовать графический вывод на экран от Nokia1100. После некоторого размышления над этим, я приступил к написанию второй версии библиотеки для работы с дисплеем Nokia 1100 в графическом режиме. И вот результат моей работы.

Первая версия библиотеки работала только в текстовом режиме. Вторая версия библиотеки по функционалу частично повторяет библиотеку версии 1, но она имеет и кардинальное отличие. В этой версии библиотеки используется видеобуфер в оперативной памяти. Без этого буфера реализовать работу с графикой не представляется возможным, так как дисплей от Nokia 1100 позволяет только записывать данные в память контроллера экрана PCF8814, считать данные из него невозможно, хотя контроллер PCF8814 это и позволяет. Чем руководствовались разработчики этого экрана непонятно, какие задачи стояли неизвестно, но что имеем, то имеем.

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

Буфер организован как массив размерностью 96×8 значений unsigned char. То есть массив соответствует организации видеопамяти в контроллере экрана PCF8814 — 8 банков по 96 байт (столбец из 8 пикселей)  в каждом. Т.е. по горизонтали отсчет идет в пикселях, а по вертикали в блоках по 8 пикселей.

Алгоритм работы с буфером по выводу графики такой. По логическим координатам в пикселях вычисляем соответствующий физический адрес ячейки (функция nlcd_GotoXY_pix), содержащей необходимый пиксель. Берем данные из буфера, производим соответствующую битовую операцию над  полученным значением. Затем записываем результат обратно в видеобуфер. Переходим к соответствующей ячейке в видеопамяти экрана и записываем полученный результат туда, для отображения результата на экране.

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

Для демонстрации работы с библиотекой я написал небольшой тестовый проект. Быдлокод, но для демонстрации библиотеки пойдет. Все линейно и крутится в бесконечном цикле. Вот код:

#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>

#include "nokia1100_lcd_lib.h"    // Подключаем драйвер LCD-контроллера NOKIA1100

char Text[] PROGMEM = "GRAPH DEMO INIT";

int main(void)
{

    nlcd_Init();
    _delay_ms(100);

  while(1)
  {
    nlcd_GotoXY(1,4);
    nlcd_PrintF(Text); // Выводим строку из программной памяти

    _delay_ms(4000);

    nlcd_GotoXY(0,0);

    nlcd_PrintF(PSTR(" GRAPH MODE DEMO")); // Другой способ задания строк в программной памяти
    nlcd_PrintF(PSTR("----------------"));
    nlcd_PrintF(PSTR(" DigitalChip.ru "));
    nlcd_PrintF(PSTR("    present     "));
    nlcd_PrintF(PSTR(" NOKIA 1100 LCD "));
    nlcd_PrintF(PSTR("  demonstration "));
    nlcd_PrintF(PSTR("----------------"));

    _delay_ms(8000);
//
    nlcd_GotoXY(2,7);
    nlcd_PrintF(PSTR("Clear screen"));
    _delay_ms(4000);
    nlcd_Clear();
//
    nlcd_GotoXY(1,7);
    nlcd_PrintF(PSTR("Pixel function"));

    for (unsigned char i = 0; i<96; i++)
    {
        for (unsigned char j = 0; j<57; j++)
        {
            nlcd_Pixel(i,j,PIXEL_ON);
            j++;
        }
        i++;
    }
    _delay_ms(4000);
//
    nlcd_Clear();
    nlcd_GotoXY(0,7);
    nlcd_PrintF(PSTR("Line function   "));

    nlcd_Line (3,4,90,41, PIXEL_ON);
    nlcd_Line (95,0,30,55, PIXEL_ON);
    nlcd_Line (20,20,70,60, PIXEL_ON);

    _delay_ms(4000);

//
    nlcd_Clear();
    nlcd_GotoXY(0,7);
    nlcd_PrintF(PSTR("Circle function "));

    nlcd_Circle(50,30,20, FILL_OFF, PIXEL_ON);
    _delay_ms(4000);

//
    nlcd_GotoXY(0,7);
    nlcd_PrintF(PSTR("Fill circle     "));

    nlcd_Circle(40,25,15, FILL_ON, PIXEL_ON);
    _delay_ms(4000);
//
    nlcd_GotoXY(0,7);
    nlcd_PrintF(PSTR("Fill rectangle  "));

    nlcd_Rect (10,10,55,38,FILL_ON, PIXEL_ON);
    _delay_ms(4000);

//
    nlcd_GotoXY(0,7);
    nlcd_PrintF(PSTR("Rectangle invers"));

    nlcd_Rect (20,20,45,34,FILL_OFF, PIXEL_INV);
    _delay_ms(4000);

//
    nlcd_GotoXY(0,7);
    nlcd_PrintF(PSTR("Pixel inversion "));

    for (unsigned char i = 0; i<96; i++)
    {
        for (unsigned char j = 0; j<57; j++)
        {
            nlcd_Pixel(i,j,PIXEL_INV);
            j++;
        }
        i++; i++;
    }
    _delay_ms(4000);
//

    nlcd_Clear();

    nlcd_PrintF(PSTR(" GRAPH MODE DEMO"));
    nlcd_PrintF(PSTR("----------------"));
    nlcd_PrintF(PSTR("   End of demo  "));
    nlcd_PrintF(PSTR("                "));
    nlcd_PrintF(PSTR("   see more on  "));
    nlcd_PrintF(PSTR(" digitalchip.ru "));
    nlcd_PrintF(PSTR("----------------"));

    _delay_ms(8000);

    nlcd_Clear();
   }
}

Ну и небольшое видео по работе этой программки:

YouTube video

Ну вот, собственно, и все. Какую версию библиотеки использовать — решать вам. Если вы работаете только с текстом (меню там всякие, сообщения и т.д.), то целесообразно применять версию 1. Она занимает меньше места, компактная и не использует ОЗУ для хранения буферов. Самое то для ограниченных в ресурсах микроконтроллеров.

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

За сим откланиваюсь. Велком в комментарии.

Скачать

NOKIA1100_3.c — демонстрационный проект
Файлы библиотеки:
nokia1100_lcd_lib.h
nokia1100_lcd_lib.c
nokia1100_lcd_font.h

nlcd11100_graph_2.1.zip — библиотеке в zip-архиве

Прошивка демо-проекта — откомпилированный проект

VSM-модели экранов Nokia для Proteus

[Свернуть]

Вливайтесь в обсуждение

  27 комментариев

  • Евгений

    8 лет назад

    Файлов таких нету. Их нельзя скачать. Поправьте пожалуйста ссылки на них.
    nokia1100_lcd_fnt.h

     
    nlcd11100_graph_2.0.zip — библиотеке в zip-архиве

  • Извините, просто это старая ссылка. Библиотека обновлена, выложены новые файлы, а ссылки на эти файлы отвалились… 🙁

    Поправил.

    Но лучше качать здесь: http://digitalchip.ru/opisanie-funktsiy-graficheskoy-biblioteki-dlya-lcd-ekrana-ot-nokia-1100. Выкладываться новые версии будут туда.

  • Андрей

    7 лет назад

    А можно ли этой графической библиотекой работать с lcd nokia 1110 без изменений или придется переписывать какие-то функции?

    • Можно. Ничего переписывать не нужно. Просто нужно немного настроить под экран — в начале заголовочного файла библиотеки поправить define (размер экрана). И все.

      • Андрей

        7 лет назад

        это хорошо) правда вы говорили, что эти экраны медленные, зато они у нас в магазине стоят 85р., а 1100 стоит 200р.

        • Поиграйтесь параметром #define NLCD_MIN_DELAY

           Может у вас заработает при 0. Тогда дисплей по скорости нормальный будет. Все мои экраны это позволяли — работать при нулевой задержке — и были довольно шустрыми. Кроме 1100. Там минимальная задержка 34. А это медленно.

  • Андрей

    7 лет назад

    Компелирую в Arduini IDE. Выдаёт много ошибок наподобии: test2.ino: In function ‘int main()’:
    test2:18: error: invalid conversion from ‘char*’ to ‘unsigned char*’

    • Ну так замените везде char* на unsigned char*. Это не принципиально.

      • Андрей

        7 лет назад

        Хм, а скажите, чем ему не нравится оператор for, в каждой функции где он есть for(unsigned int i=0;i<864;i++) nlcd_SendByte(DATA_LCD_MODE,0x00);   ?
        вот такие ошибки: …\nokia1100_lcd_lib.c:88: error: ‘for’ loop initial declaration used outside C99 mode

        • В ANSI C нельзя объявлять переменные внутри цикла for/while

          правильно будет примерно так:
          unsigned int i;
          for(i = 1; i < 864; i++) {
          nlcd_SendByte(DATA_LCD_MODE,0×00);
          }

          • Андрей

            7 лет назад

            Если использовать шрифт 10х16, как правельно его вывести чтоб нижняя часть была не за верхней а под ней? Спасибо.

          • Андрей

            7 лет назад

            Всё, со шрифтом разобрался. Русские не печатает ((( Для вывода русского что то ещё надо делать?

  • rastamanoff

    6 лет назад

    Здравствуйте!
    Юзаю Вашу библиотеку,с LCD NOKIA 1100.Дисплей взят от ненужного сотового.
    Запустил демо проекты — текст и графика.Работает,но вот незадача : первая строчка изображения или текста начинает выводится на экран не с верху (nlcd_GotoXY(0,0);),а снизу.Тоесть первая строчка внизу ,вторая вверху экрана и тд.
    Разрешение дисплея в пикселях выставил :

    #define NLCD_X_RES 96 // разрешение по горизонтали
    #define NLCD_Y_RES 65 // разрешение по вертикали

    В чем может быть проблема?

    • Странно, не встречался с таким случаем. Может в вашем дисплее другой контроллер стоит, не PCF8814?

      • rastamanoff

        6 лет назад

        Я тоже в непонимаю в чем дело.Дисплей «выковырян» с мобилки,на внутреней крышке надпись — Nokia Corporation,Type:RH-18,Model:1100.
        Вот что-бы вывести показания с DS1307,и получить вот такую картинку-http://radiomanoff.at.ua/lcd1100/IMG_20140502_192507_01-001.jpg
        в коде пишу так

        sprintf(array, «%02d:%02d:%02d», hour, minute, second );
        sprintf(array_2, » %02d», date);
        sprintf(array_4, «20%02d год», year);

        nlcd_GotoXY(1,2);//получается верхняя строчка
        nlcd_PrintWide(array);//выодит часы,минуты,секунды

        nlcd_GotoXY(3,4);
        //функция вывода дня недели
        if(week == 1) nlcd_Print(«понедельник»);
        else if (week == 2) nlcd_Print(«вторник»);
        else if (week == 3) nlcd_Print(«среда»);
        else if (week == 4) nlcd_Print(«четверг»);
        else if (week == 5) nlcd_Print(«пятница»);
        else if (week == 6) nlcd_Print(«субота»);
        else nlcd_Print(«воскресенье»);

        nlcd_GotoXY(0,6);
        nlcd_PrintWide(array_2);//выводит день месяца

        if(month == 1) nlcd_Print(» января»);
        else if (month == 2) nlcd_Print(» февраля»);
        else if (month == 3) nlcd_Print(» марта»);
        else if (month == 4) nlcd_Print(» апреля»);
        else if (month == 5) nlcd_Print(» мая»);
        else if (month == 6) nlcd_Print(» июня»);
        else if (month == 7) nlcd_Print(» июля»);
        else if (month == 8) nlcd_Print(» августа»);
        else if (month == 9) nlcd_Print(» сентября»);
        else if (month == 10) nlcd_Print(» октября»);
        else if (month == 11) nlcd_Print(» ноября»);
        else nlcd_Print(» декабря»);

        nlcd_GotoXY(0,0);
        nlcd_PrintWide(array_4);//выводит год

    • rastamanoff

      5 лет назад

      Здравствуйте!
      Юзаю Вашу библиотеку,с LCD NOKIA 1100.Дисплей взят от ненужного сотового.
      Запустил демо проекты — текст и графика.Работает,но вот незадача : первая строчка изображения или текста начинает выводится на экран не с верху (nlcd_GotoXY(0,0);),а снизу.Тоесть первая строчка внизу ,вторая вверху экрана и тд.

      Проблема решена,достаточно при инициализации строку
      lcd1100_write(lcd1100_CMD,0xac); //Выставить начальный ряд (R0) дисплея
      поменять на
      lcd1100_write(lcd1100_CMD,0xa8); //Для оригинала Nokia1100

      Все выплыло с мануала на pcf8814 — таблица 18(значения С2,С1,С0 — 000)

      А дисплей заводской,выковырян с рабочей мобилки

  • rastamanoff

    6 лет назад

    Спасибо большое за библиотеку.
    Вот сделал небольшой отчет о проделаной работе — http://radiomanoff.at.ua/index/lcd_nokia1100/0-55#

  • Здравствуйте!
    Большое Спасибо за библиотеку!
    Возник вопрос почему размер видеобуфера выбран так странно
    static unsigned char nlcd_memory[NLCD_X_RES-1][(NLCD_Y_RES/8)+1];
    У меня при этом программа виснет.
    если же поставить
    static unsigned char nlcd_memory[NLCD_X_RES][(NLCD_Y_RES/8)];
    то все работает нормально.

    • Точнее (NLCD_Y_RES/8)+1 — понятно почему, а вот
      NLCD_X_RES-1 — не понятно?

      • Потому что отсчет индекса в буфере идет от нуля, а размер задается от 1. Вобщем-то то стандартный прием…

        • sizeof( nlcd_memory[NLCD_X_RES-1][(NLCD_Y_RES/8)+1] )=855
          sizeof( nlcd_memory[NLCD_X_RES][(NLCD_Y_RES/8)+1] )=864
          в комментариях написано: 9 банков по 96 байт, а выделяется 855 байт, поэтому после выполнения процедуры nlcd_Clear() в которой есть строка
          for(i=0;i<864;i++) nlcd_SendByte(DATA_LCD_MODE,0x00);
          происходит повреждение данных, которые располагаются в памяти непосредственно
          за nlcd_memory.

  • Серга

    5 лет назад

    с экраном 1202 будет работать ?
    если нет то нет ли библиотек для 1202 ?
    самыё дешёвый и простой в пайке дисплей всё-таки

Добавить комментарий

Отправляя комментарий, вы автоматически принимаете правила комментирования на сайте.

Правила комментирования на сайте:

  1. Не следует писать исключительно заглавными буквами. Это дурной тон.
  2. Запрещены комментарии не относящиеся к тематике сайта и самой статье.
  3. Запрещены реплики оскорбляющие других участников проекта. Давайте будем взаимовежливы.
  4. Запрещены нецензурные слова, идиоматические выражения, призывы к межнациональной и межконфессиональной розни.
  5. Запрещено обсуждение наркотических веществ и способов их применения.
  6. Запрещены комментарии с призывами к нарушению действующего законодательства РФ (Уголовного и Административного кодекса).
  7. Запрещены ссылки на сторонние ресурсы без согласования с владельцем сайта.
  8. Запрещается использовать в качестве имени комментатора слоганы/названия сайтов, рекламные фразы, ключевые и т.п. слова.

Следует учитывать следующее - все комментарии проверяются на предмет отсутствия спама. При обнаружении признаков спама, в оставленном Вами комментарии, сам комментарий будет незамедлительно удален, а Ваш IP-адрес будет добавлен в черный список без предупреждения!

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