Работаем с дисплеем от 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();
   }
}

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

Ну вот, собственно, и все. Какую версию библиотеки использовать — решать вам. Если вы работаете только с текстом (меню там всякие, сообщения и т.д.), то целесообразно применять версию 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 комментариев на “Работаем с дисплеем от Nokia 1100 в графическом режиме”

  1. Евгений

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

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

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

    Поправил.

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

  3. А еще тут посмотрите: http://digitalchip.ru/obnovlenie-biblioteki-vyivoda-dlya-displeev-nokia

  4. Андрей

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

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

      • Андрей

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

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

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

  5. Андрей

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

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

      • Андрей

        Хм, а скажите, чем ему не нравится оператор 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);
          }

          • Андрей

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

          • Андрей

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

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

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

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

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

      • Я тоже в непонимаю в чем дело.Дисплей «выковырян» с мобилки,на внутреней крышке надпись — 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);//выводит год

    • Здравствуйте!
      Юзаю Вашу библиотеку,с 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)

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

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

  8. Здравствуйте!
    Большое Спасибо за библиотеку!
    Возник вопрос почему размер видеобуфера выбран так странно
    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.

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

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

Поля, помеченные знаком звездочка (*) обязательны для заполнения.