В этой записи хочу поделиться опытом и готовыми библиотеками для работы с графическим дисплеем от Nokia 3110 (5110) для подключения к микроконтроллерам STM32, а, в частности, к STM32F100. Однако, не составит труда переделать для работы с микроконтроллерами семейства STM32F4. Давайте для начала разберемся Как работает графический дисплей.
Экран от Nokia 3110 представляет собой графический жидко-кристаллический дисплей с размером видимой части 84 на 48 точек. Управляется матрица контроллером PCD8544, даташит на него в конце статьи. Связь с контроллером осуществляется через последовательный интерфейс, что-то на подобии SPI.
Для управления дисплеем необходимо подключить следующие линии:
1) RST – Reset – линия сброса. Для сброса необходимо подать сюда 0. В рабочем режиме линия должна быть подтянута к Vcc.
2) CE – Chip Enable – линия выбора устройства на шине данных. При передачи данных дисплею – опустить к общему (лог.0). В режиме ожидания – к Vcc.
3) DC – Data/Command – выбор типа данных – передача команды (лог.0) или информации в память дисплею (лог.1).
4) Din – Data in – линия данных.
5) Clk – Clock – линия для такта.
6) Vcc и Gnd – линии для питания.
Хочу обратить внимание, что дисплею и уровни на входе должны быть 3.3В, хотя встречаются и на 5В. Этот момент необходимо уточнять в каждом конкретном случае.
Итак, подключаем согласно этому к отладочной плате STM32F100: RST – PA0, CE – PA1, DC – PA2, Din – PA3, Clk – PA4.
Вся матрица экрана разделена на 6 строк (банков) и 84 столбца, т.е. получается 84 байта в ряду. Передача информации происходит побайтно. Передается вначале старший бит.
А вот так выглядит адресация в памяти дисплея:
И, конечно, контроллер поддерживает автоматическое смещения указателя адреса при непрерывной передачи данных. Есть два варианта: горизонтальное смещение и вертикальное. Будем использовать горизонтальное (в клеточках – номер байта при непрерывной передачи):
Теперь перейдем к разбору как оживить дисплей. Я использовать буду CooCox IDE, но это не принципиально. Как обычно, для удобства, я сделал структуру, в которой указываются линии подключения дисплея, внешняя функция задержки и указатель на переменную, где хранится информация о точках на экране.
1 2 3 4 5 6 7 8 9 |
N5110_TypeDef LCD = { {GPIOA, GPIO_Pin_0}, {GPIOA, GPIO_Pin_1}, {GPIOA, GPIO_Pin_2}, {GPIOA, GPIO_Pin_3}, {GPIOA, GPIO_Pin_4}, Delay_US, &m }; |
где m это матрица для хранения информации о точках экрана:
1 |
N5110_Bitmap_TypeDef m; |
Для инициализации интерфейса необходимо вызвать N5110_Init() и передать указать на структуру:
1 |
N5110_Init(&LCD); |
Хочу обратить внимание, что все настройки портов и пинов выполнятся автоматически. При использовании других контроллеров (не F100), необходимо будет переделать эту функцию.
Ну и все, дисплей готов к работе. Опишу небольшое API моей библиотеки:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
Нарисовать символ размером 6*8 точек. Для добавления символов см. font.h N5110_WriteChar(N5110_TypeDef* lcd, uint8_t x, uint8_t y, uint8_t c); Тоже самое, что и предыдущая функция, только выводит инверсно символ N5110_WriteCharInv(N5110_TypeDef* lcd, uint8_t x, uint8_t y, uint8_t c); Очищает экран N5110_Clear(N5110_TypeDef* lcd); Переход к произвольной точке на экране. Отсчет от 0 N5110_GotoXY(N5110_TypeDef* lcd, uint8_t X, uint8_t Y); Вывести на экран строку N5110_WriteString(N5110_TypeDef* lcd, uint8_t x, uint8_t y, uint8_t *s); Выводит число на экран N5110_WriteDec(N5110_TypeDef* lcd, uint8_t x, uint8_t y, uint16_t buffer); Перерисовать экран N5110_Refresh(N5110_TypeDef* lcd); Нарисовать произвольную точку N5110_DrawPixel(N5110_TypeDef* lcd, uint8_t X, uint8_t Y); Очищает произвольную точку на экране N5110_ClearPixel(N5110_TypeDef* lcd, uint8_t X, uint8_t Y); Рисует линию N5110_DrawLine(N5110_TypeDef* lcd, uint8_t X1, uint8_t Y1, uint8_t X2, uint8_t Y2); Рисует окружность N5110_DrawCircle(N5110_TypeDef* lcd, uint8_t X, uint8_t Y, uint8_t R); Рисует прямоугольник N5110_DrawRect(N5110_TypeDef* lcd, uint8_t X1, uint8_t Y1, uint8_t X2, uint8_t Y2); Рисует "часовую стрелку" N5110_DrawClock(N5110_TypeDef* lcd, uint8_t X, uint8_t Y, uint8_t r, uint8_t ang); |
Стоит уделить внимание N5110_Refresh(). Эта функция перерисовывает экран по той информации, что содержится в переменной m. Поэтому, можно напрямую изменять ее и потом перерисовывать экран, так можно немного оптимизировать анимацию.
В заключении хочу сказать, что эта библиотека не является панацеей, и скорее всего часть функций можно будет выкинуть в реальном проекте, либо, наоборот, добавить. Ну и, конечно, там есть куча мест, где стоит оптимизировать алгоритм, но это уже я оставляю на читателя. Если есть вопросы по работе, то прошу их задавать не стесняясь :)
Файлы:
1) Проект в CooCox IDE Nokia 5110 LCD vs STM32
2) Даташит на контроллер дисплея PCD8544
3) Видео на YouTube Nokia 5110 LCD vs STM32
Хорошо Вам… У меня не работает… STM32F103C8T6. Что в проге изменить?
Что такое green_on() ?
green_on(), green_off(), blue_on(), blue_off() эио функции для включения или выключения светодиодов на плате дискавери (там зеленый и синий они на портах С.8 и С.9).
А что именно не работает? Как проявляется? Код компилируется?
Спасибо за ответ. Дисплейчик зевёлся.
Как в Вашем коде изменить пины подключения дисплея? Мне нужно так:
#define LCD_PORT GPIOB
#define LCD_DC_PIN GPIO_Pin_14
#define LCD_CE_PIN GPIO_Pin_13
#define LCD_RST_PIN GPIO_Pin_12
#define LCD_SDIN_PIN GPIO_Pin_15
#define LCD_SCLK_PIN GPIO_Pin_11
Михаил, смотрите в main.c, там есть структура LCD типа N5110_TypeDef, в ней задаются порт и пин для каждой линии. Нужно в коде примера поменять на это:
N5110_TypeDef LCD = {
{GPIOB, GPIO_Pin_12},
{GPIOB, GPIO_Pin_13},
{GPIOB, GPIO_Pin_14},
{GPIOB, GPIO_Pin_15},
{GPIOB, GPIO_Pin_11},
Delay_US,
&m
};
Это должно рабоать.
Всё работает, спасибо.
Функция N5110_WriteDec выводит только 3 цифры. Так и надо? А как вывести десятичное число?
4 цифры. Но с десятичными надо разбираться…
Стаття дуже хороша і пізнавальна! Публікуйте побільше, будемо дуже вдячні.
Далее захотел подключить дисплей от Нокии 3110 и выводить данные на него. Дисплей подключен и работает нормально, тестовые программы на нём выполняются. Но при попытке отразить на дисплее данные, получаемые от блока часов на экране отображаются символы псевдографии, а часов как таковых нет.
Лицевая часть корпуса сделана из глянцевого пластика, который очень быстро пачкается. Следы пальцев и рук остаются как на поверхности экрана, так и на клавиатурном блоке. За счет маркости корпус теряет во внешнем виде, приходится постоянно протирать поверхность или смириться с тем, что лицевая сторона будет переливаться отпечатками пальцев и другими следами.
Да, действительно такое есть у этих экранов. Но это практически у всех так. Рекомендуется использовать защитное стекло, чтобы защитить саму матрицу.
Библиотека рабочая, благодарю! Но на двух разных индикаторах (один как ваш на видео, другой – с запараллелеными выводами на противоположных краях платы) функция N5110_WriteCharInv() работала странно – выводимый символ оказывался после последнего выведенного символа, а не в указанных координатах. Сделал эту функцию также, как и N5110_WriteChar(), только переставил местами вызовы N5110_ClearPixel() и N5110_DrawPixel() – стало нормально. Заодно и N5110_WriteStringInv() сделал.
Классная статья
Спасибо за библиотеку. Она и в правду рабочая… Работает без каких либо проблем… Спасибо….