02.05.2012
Библиотека вывода на lcd-экраны Nokia

Обновление библиотеки вывода для дисплеев Nokia

После того, как Валерий Гончаренко сделал приятный подарок в виде нескольких дисплеев Nokia, я немного переработал свою библиотеку вывода для дисплеев Nokia. Изменения коснулись обоих вариантов библиотеки, как графической (2.1), так и текстовой (1.1). В графический вариант внесено больше изменений, чем в текстовый, добавлены несколько новых функций.

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

Варианты и версии библиотеки

Текстовый вариант библиотеки имеет нумерацию 1.x и содержит только функции вывода на экран текстовой информации. Занимает в памяти программ минимум места и не создает никаких буферов в оперативной памяти. Содержит только функции вывода текста на экран. Рекомендуется для микроконтроллеров AVR с минимумом системных ресурсов (программной и оперативной памяти).

Второй вариант библиотеки — графический. Имеет нумерацию 2.x и содержит весь набор функций текстового варианта с добавлением функций для работы с графикой. В отличии от текстового варианта занимает намного больше памяти, как программной, так и оперативной. В оперативной памяти создается видеобуфер, содержащий копию того, что выведено на экран, так как дисплеи от Nokia позволяют только записывать данные в контроллер дисплея (хотя сам контроллер позволяет как записывать, так и читать данные). Буфер занимает в памяти 864 байта, плюс еще несколько переменных. Соответственно, применять этот вариант библиотеки можно на микроконтроллерах, которые имеют достаточное количество оперативной памяти.

Скорость работы

Основной претензией к работе библиотеки с экранами Nokia, в частности экраном Nokia 1100, было низкое быстродействие. Этот дисплей от Nokia 1100 можно было назвать супертормозным. Библиотека имеет параметр NLCD_MIN_DELAY (задается в файле nokia1100_lcd_lib.h). Это минимальная задержка при передаче байтов данных в контроллер дисплея. Так вот, в первой версии библиотеки (как 1.0, так и в 2.0) этот параметр имел значение 270 микросекунд для дисплея  Nokia 1100! Передача данных в контроллер дисплея была очень медленной. При меньшей задержке вывод на экран не работал. В отличии от 1100 в дисплеях Nokia 1202 можно было (да и сейчас это можно, и даже нужно) установить задержку в 0, после чего вывод на экран происходит мгновенно.

Во второй версии (именно версии, не варианте) библиотеки (1.1 и 2.1) ускорена работа с дисплеем, причем на порядок. Теперь минимальная задержка при передаче данных в контроллер 1100 — 34 микросекунды! Сравните: 270 было, 34 стало  (1202 работает при 0 — рекордсмен по скорости). Теперь вывод на экран стал намного более приемлемым. Реализовано это дополнительным командами инициализации.

Ошибка в видеобуфере

Так как изначально библиотека писалась под единственный имеемый в наличии дисплей Nokia 1100, то в расчетах при написании были допущены ошибки, которые устранены во второй версии библиотеки. Теперь размер буфера вычисляется автоматически по заданным параметрам. Сейчас можно задать параметр разрешения дисплея (файл nokia1100_lcd_lib.h) и использовать библиотеку с дисплеями с разным разрешением экрана, но со сходной системой команд.

Кодировка символов

Раньше вывод символов кириллицы был реализован частично в кодировке CP866. Теперь вывод символов реализован с кодировкой CP1251 (win1251), как более распространенной. Выводятся только символы кириллицы, псевдографика не выводится.Т.е. теперь не нужно подготавливать специальным образом строки для вывода кириллицы. Просто пишем nlcd_Print («Велик и могуч русский язык!»); и все работает корректно.

Про модификацию библиотеки под эту кодировку писал Maxim Grigorov в своем блоге. С точки зрения программиста изменения у него реализованы более грамотно, через функцию lcd_symbol_decode(c), но я сделал без функции, напрямую. Вызов функции занимает некоторое время (минимальное, но все же), а у меня пересчет идет прямо в процедуре вывода символа. Без всяких проверок на корректность данных, незачем тратить время на ерунду, мы не для настольных компьютеров быдлокодим программируем, нам каждый байт дорог :).

Вывод символов двойной ширины

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

Прототип функции:
void nlcd_PrintWide(unsigned char * message);

Используется точно также как и nlcd_Print.

Тест широкого шрифта на экране Nokia 1100

Тест широкого шрифта на экране Nokia 1100

Тест широкого шрифта на экране Nokia 1202

Тест широкого шрифта на экране Nokia 1202

Разрешение экрана

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

// Разрешение дисплея в пикселях
#define NLCD_X_RES    96        // разрешение по горизонтали
#define NLCD_Y_RES    68        // разрешение по вертикали

Работать с разрешением в функциях стало проще, теперь не надо править всю библиотеку под свой экран, если разрешение отличается от принятого в 1100 (96×65). Выше в примере заданы размеры экрана 1110i и 1202.

Вывод прямоугольника

Исправил ошибку в функции рисования прямоугольника. Проявлялась при рисовании с параметром наложения PIXEL_INV.

Вывод изображений

Ну и как же без вывода картинок. Написал первую версию этой процедуры. Куча ограничений. Практически никаких проверок на корректность данных. Зато работает очень быстро.

Долго сидел и думал, как ее написать. Можно написать при помощи функции nlcd_Pixel, т.е. выводить изображение попиксельно. Можно реализовать практически все проверки на корректность и т.д. Но работать будет очень долго. Это не наш путь.

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

Ограничения заключаются в том, что размер картинки по вертикали должен быть кратен 8. По горизонтали — без ограничений (в разумных пределах). Затем, координаты вывода левого верхнего угла картинки по вертикали опять же должны быть кратны 8. По горизонтали — без ограничений. Если функцию вызвать, например, с такими параметрами: nlcd_Pict (10,10,picture);, то картинка picture будет выведена по координатам: по горизонтали 10, во вертикали 8 (левый верхний угол картинки). Т.е. вертикальная координата приводится к значению, кратному 8.

Еще одно из ограничений в том, что картинка должна хранится в программной памяти, так как используется pgm_read_byte (). Думаю, что это логично, так как картинки занимают довольно много памяти, и хранить их в оперативке — не наш метод.

Картинки имеют следующий формат:

  • байт 0 — размер по горизонтали в пикселях (без ограничений, но в разумных пределах);
  • байт 1 — размер по горизонтали в пикселях (кратный 8);
  • далее массив данных побайтно (столбец из 8 бит) и построчно. Единица в значении бита говорит о том, что пиксел зажжен (светится).

Для подготовки данных, по подсказке Валерия Гончаренко (thanx), использую программу от Alex_EXE. После получения массива с данными картинки, добавьте в начало массива два байта с размером картинки по горизонтали и по вертикали (ну и размер массива нужно изменить на 2 байта).

Генератор картинок

Генератор картинок

В итоге должно получится что-то типа этого:
PROGMEM static const char nlcd_image[] =
{ 24,24,
0x00, 0x00, 0x00, 0x00, 0x40, 0x60, 0xE0, 0xE0, 0x60, 0x60, 0x60, 0x60,
0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00,
0x00, 0xE0, 0x78, 0x1F, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0xFF,
0x01, 0xFF, 0xFE, 0xFF, 0xDB, 0xDB, 0xDB, 0x00, 0xFF, 0xC0, 0xC0, 0x00,
0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07,
0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x02, 0x00};

Еще раз обращаю внимание, что картинки должны хранится в программной памяти. Не забываем!

Ну и вывод этой картинки выглядит так:
nlcd_Pict(40,8,nlcd_image);

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

Nokia 1100 - картинка 1

Nokia 1100 - картинка 1

Nokia 1100 - картинка 2 - инверсная

Nokia 1100 - картинка 2 - инверсная

Nokia 1202 - картинка 1

Nokia 1202 - картинка 1

Nokia 1202 - картинка 2 - инверсная

Nokia 1202 - картинка 2 - инверсная

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

Сравнение отображения экранов Nokia 1100 и 1202

Сравнение отображения экранов Nokia 1100 и 1202

На экране 1202 картинка чуть более контрастная, чем на 1100. Но сам экран чуть меньше, чем 1100. На фотке видно, что вертикальное разрешение у 1202 чуть больше, чем у 1100 (68 против 65).

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

 

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

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

  • подкиньте примеры менюшек текстовых!
    выбор менюшки по кнопке или жнкодером
    Буду очень признателен!

  • всем привет
    подключаю десплей 1100 к ардуинке пробую залить какой нибуть код и вот такая ошибка

    avrdude: stk500v2_ReceiveMessage(): timeout
    avrdude: stk500v2_ReceiveMessage(): timeout
    avrdude: stk500v2_ReceiveMessage(): timeout
    avrdude: stk500v2_getsync(): timeout communicating with programmer

    [Stino — Exit with error code 1.]

    а если в стандартной IDE пытаюсь залить то вот такая

    Hello_World.ino: In function ‘void setup()’:
    Hello_World.ino:6:6: error: redefinition of ‘void setup()’
    sketch_jun13b.ino:1:6: error: ‘void setup()’ previously defined here
    Hello_World.ino: In function ‘void loop()’:
    Hello_World.ino:16:6: error: redefinition of ‘void loop()’
    sketch_jun13b.ino:6:6: error: ‘void loop()’ previously defined here
    Ошибка компиляции.
    што делать?
    зарание спасибо

  • не увидел нигде версии текстовой 1.1 с поддержкой 1202
    вообще библиотека универсалная а название ёё неё nokia1100_lcd_
    создают значительные нестыковки в мозгу.

  • Никифор

    3 года назад

    Добрый день.
    пишите что надо для 1100 задержку делать.
    посмотрел код там задержка каждый такт. Правда эксперементиовал с дисплеем 2100 и там самое главное задержка после передачи. т.е можно передавать с максимальным бодрейтом, но дать время на обработку команды после передачи.

    может и на 1100 также ?

  • Marina Zemina

    2 года назад

    Здравствуйте! Таким образом занятыми окажутся от 6-ти до 11-ти контактов от обоих устройств. Если вам не требуется считывать с дисплея, что подходит под большинство сценариев использования, для команд понадобится 2 линии.

  • Библиотека хорошо работает, все выводит и строки и рисунки.
    А как быть если есть к примеру переменная с плавающей точкой. Как ее вывести?

    #include

    PCF8814 Lcd(13,11,10,6); // SCLK, SDA, CS, RESET.

    String s; char Text[] = «Русский ТЕКСТ»; float volts=18.3;

    void setup() {
    Serial.begin(9600);
    Lcd.Init();
    delay(100);
    Lcd.Contrast(0x0F);// 0х00 — 0х1F
    Lcd.GotoXY(0);
    Lcd.Print(«ДОБРОЕ УТРО++»);
    Lcd.GotoXY(1,2);
    Lcd.PrintWide(«СТРАНА»);
    Lcd.GotoXY(1,4);
    Lcd.Print(Text); // Выводим строку из программной памяти

    }

    void loop() {

    s = «U1 «+String(volts);
    Serial.println(s); // в монитор порта выводит

    //val = String(va/10, DEC); val += «.»; val += String(va%10, DEC);

    Lcd.GotoXY(0,6);
    Lcd.Print(«12,9 «); Lcd.Print(«4,7 «);
    //Lcd.Print(«18,9»);
    Lcd.Print(s); // ошибка компилятора
    delay(1000);

    }

    • Есть несколько вариантов. Выводить библиотека может только текстовые строки. Что бы выводить числа, их нужно перевести в текст.
      Что бы перевести вещественные числа в текст в среде Ардуино есть несколько способов:
      1. Использовать библиотеку floatToString
      2. Использовать sprintf() с набором параметров форматирования
      3. Использовать функцию dtostrf() с набором параметров
      4. Написать свою функцию перевода типа такой:

      // Converts a floating-point/double number to a string.
      void ftoa(float n, char* res, int afterpoint) {
      // Extract integer part
      int ipart = (int)n;
      // Extract floating part
      float fpart = n - (float)ipart;
      // convert integer part to string
      int i = intToStr(ipart, res, 0);
      // check for display option after point
      if (afterpoint != 0) {
      res[i] = '.'; // add dot
      // Get the value of fraction part upto given no.
      // of points after dot. The third parameter
      // is needed to handle cases like 233.007
      fpart = fpart * pow(10, afterpoint);
      intToStr((int)fpart, res + i + 1, afterpoint);
      }
      }

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

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

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

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

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

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