Разбираемся с LCD экраном LPH9157-2 от Siemens C75/ME75
Внятной документации на этот экран я не нашел поэтому пришлось разбираться с тем что есть и экспериментировать. В качестве управляющего устройства я использовал Raspberry PI. Так-же была написана программа позволяющая превратить этот экран в мини-монитор.
Описание
Данный дисплей имеет разрешение 132 x 176 пикселей и даёт возможность работать с тремя цветовыми палитрами 16(5-6-5), 12(4-4-4) и 8(3-3-2) бит.
Распиновка и подключение
Тут всё просто, экран питается напряжением 2,9 вольт, подсветка (LED±) запитывается отдельно напряжением примерно 12 вольт(я использовал батарею аккумуляторов соединённую с подсветкой через резистор на 510 Ом).
Pin description# | Name | Function |
1 | RS | Low=CMD, High=DATA |
2 | ~RST | Reset input, active low |
3 | ~CS | Chip select, active low |
4 | SYNC | External frame synchorization input, unused by default |
5 | CLK | SPI Clock-in signal (High-to-Low) |
6 | DATA | SPI Data-in signal (MSB first) |
7 | VCC | Power supply, normally 2.9V (I tested with 3.3V) |
8 | GND | Ground |
9 | LED+ | Backlight voltage, approx. 12V (depends on required current) |
10 | LED- | Backlight common pin |
Как можно заметить экран управляется через интерфейс SPI (контакты CS/CLK/DAT(MOSI)), предположительно это лишь половина интерфейса так как отсутствует контакт MISO, следовательно писать данные в экран мы можем, а вот читать — нет(здесь следует упомянуть что SPI может работать в двунаправленном режиме с использованием одного провода (MIMO) но так как отсутствует какие либо команды чтения данных из экрана будем считать что этот режим экраном не используется).
И перед тем как переходить непосредственно к управлению экраном надо бы этот экран к чему-нибудь подключить. В моём случае это будет Raspberry Pi. Контакты SPI экрана подключены к соответствующим им контактам SPI «малины», RS и RST к GPIO_17 и GPIO_27 соответственно. Данное подключение актуально для RPI Revision-2, если у вас иная модель то названия и номера контактов GPIO могут отличаться.
Заморачиваться с разъёмом подключения экрана я не стал и просто подпаялся к выводам проводом МГТФ. Экран в данном подключении питается от 3.3В, а не от 2.9 как в описании. Вот так выглядит вся схема в сборе
Команды управления экраном
Экран управляется достаточно просто — путём посылки по SPI команд и данных. Отличить одни от других экрану помогает состояние пина RS где высокий уровень(лог. 1) означает передачу данных, а низкий(лог. 0) передачу команд. При передаче используется тупоконечный(big-ending) порядок байт.
Список команд:
- CMD_RESET 0x01 — программный сброс
- CMD_MEMORY_ACCESS_CONTROL 0x36 — установка направления заполнения области дисплея, имеет однобайтовый аргумент 0bVHRXXXXX, где V — заполнение по вертикали (0 — сверху-вниз, 1 — снизу-вверх), H — заполнение по горизонтали (0 — слева-направо, 1 — справа-налево),R — меняются местами строки и столбцы (при этом заполнение остается сверху-вниз, слева-направо))
- CMD_WAKEUP 0x11 — выход из спящего режима
- CMD_PALETTE 0x3A — установка цветовой палитры 8(0x02), 12(0x03) и 16(0x05) бит
- CMD_ENABLE 0x29 — включение дисплея
- CMD_SET_X 0x2A — задаем область рисования по X
- CMD_SET_Y 0x2B — задаем область рисования по Y
- CMD_START_WRITE 0x2C — начало записи в видеопамять
Код
Работа экрана была проверена во всех 3х цветовых режимах но, дабы не захламлять исходник, далее я буду рассматривать только 16-битный.
Во всех остальных режимах работа экрана не отличается, за исключением, разве что 12-битного — в нём на 2 пикселя приходится 3 байта, а если нужно вывести лишь одну точку то посылается 2 байта(4 младших бита последнего экраном игнорируются).
Для доступа к GPIO «малины» была использована библиотека bcm2835.
Начальная инициализация GPIO
int init_gpio()
{ if (!bcm2835_init()) return 0; bcm2835_spi_begin(); bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_MSBFIRST); // CPOL = 0, CPHA = 0, Clock idle low, data is clocked in on rising edge, output data (change) on falling edge bcm2835_spi_setDataMode(BCM2835_SPI_MODE0); // в телефоне экран работает на частоте SPI в 13 МГц
// поэтому небольшое превышение по частоте ему не повредит
// хотя у меня он продолжал работать и при вдвое большей частоте (30 МГц) bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_16); ///
Несколько вспомогательных функций
void send_cmd(char cmd)
{ bcm2835_gpio_write(LCD_RS, RS_CMD); // следующий байт – команда bcm2835_spi_transfer(cmd);
} void send_data(char data)
{ bcm2835_gpio_write(LCD_RS, RS_DATA); // следующий байт – данные bcm2835_spi_transfer(data);
}
Задание области рисования
void set_draw_area(char x1, char y1, char x2, char y2)
{ send_cmd(CMD_SET_X); send_data(x1); send_data(x2); send_cmd(CMD_SET_Y); send_data(y1); send_data(y2);
}В результате экспериментов с экраном выяснилось что необязательно задавать область перед выводом каждого кадра, достаточно задать её лишь единожды и послав команду начала записи просто гнать по SPI последовательность кадров непрерывным потоком.
Подготовка к выводу и передача данных
void draw_start()
{ send_cmd(CMD_START_WRITE); bcm2835_gpio_write(LCD_RS, RS_DATA);
} void send_draw_data(char* data, int size)
{ bcm2835_spi_transfern(data, size);
}В процессе инициализации экрана обнаружилась досадная вещь — для запуска необходимо передёрнуть RESET экрана, а вот последующие манипуляции данным выводом приводят экран в ступор и он перестаёт реагировать на внешние воздействия. Приходится сбрасывать его по питанию. Это необходимо учесть при разработке программы дабы процедура аппаратного сброса выполнялась лишь единожды.
Инициализация экрана
void reset_LCD()
{ // аппаратный сброс bcm2835_gpio_write(LCD_RESET, LOW); bcm2835_delay(50); bcm2835_gpio_write(LCD_RESET, HIGH); bcm2835_delay(50); // программный сброс send_cmd(CMD_RESET);
} void init_LCD()
{ reset_LCD(); send_cmd(CMD_MEMORY_ACCESS_CONTROL); send_data(0b00000000); send_cmd(CMD_WAKEUP); bcm2835_delay(20); send_cmd(CMD_PALETTE); send_data(_16_BIT_COLOR); bcm2835_delay(20); send_cmd(CMD_ENABLE);
}Это была подготовка, а теперь самое вкусное — попробуем вывести на экран 16-битную картинку. Первый блин как известно — комом, после запуска программы я получил довольно странное изображение, оказалось — неверный порядок байт, после исправления всё заработало.
Код
int main(int argc, char **argv)
{ if (!init_gpio()) return 1; init_LCD(); set_draw_area(0, 0, SCREEN_WIDTH – 1, SCREEN_HEIGHT – 1); draw_start(); uint16_t screen[SCREEN_HEIGHT][SCREEN_WIDTH]; FILE* f_scr = fopen(“test.
bmp”, “r”); fseek(f_scr, 0x42, SEEK_SET); // skip bmp header fread(&screen, 1, SCREEN_HEIGHT * SCREEN_WIDTH * 2/*16bit*/, f_scr); fclose(f_scr); // change byte order for(int x = 0; x > 8) | (screen[y][x] 176×132 малоинформативен, для фреймбуфера было установлено разрешение 320×240, это можно сделать правкой config.txt на FAT разделе «малиновой» флешки.framebuffer_width=320
framebuffer_height=240После этого изображение всё равно жмётся с использованием примитивной интерполяции, но результат уже можно назвать приемлемым. Так-же был добавлен пропуск одинаковых кадров для экономии CPU.Исходник LPH9157-2_RPI.c#include
#include
#include
#include #include
#include
#include // соответствия контактов GPIO и LCD
#define LCD_RS RPI_V2_GPIO_P1_11
#define LCD_RESET RPI_V2_GPIO_P1_13 #define RS_CMD 0
#define RS_DATA 1 #define CMD_RESET 0x01
#define CMD_MEMORY_ACCESS_CONTROL 0x36 // Memory Access Control
#define CMD_WAKEUP 0x11 // Выход из спящего режима
#define CMD_PALETTE 0x3A // Установка цветовой палитры
#define CMD_ENABLE 0x29 //Включение дисплея #define CMD_SET_X 0x2A // задаем область по X
#define CMD_SET_Y 0x2B // задаем область по Y
#define CMD_START_WRITE 0x2C // начало записи в память #define _8_BIT_COLOR 0x02
#define _12_BIT_COLOR 0x03
#define _16_BIT_COLOR 0x05 #define SCREEN_WIDTH 132
#define SCREEN_HEIGHT 176 int init_gpio()
{ if (!bcm2835_init()) return 0; bcm2835_spi_begin(); bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_MSBFIRST); bcm2835_spi_setDataMode(BCM2835_SPI_MODE0); /// CPOL = 0, CPHA = 0, Clock idle low, /// data is clocked in on rising edge, /// output data (change) on falling edge bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_16); ///= 0) && (fb_x + 1 = 0) && (fb_y + 1 > 1); /// ^thank you habr => http://habr.ru/p/128773/ } } } screen[y][SCREEN_WIDTH – 1 – x] = (px > 8); } send_draw_data((char*)&screen[0][0], sizeof(screen)); /// calc fps frame_cnt++; if(frame_cnt >= 100) { clock_gettime(CLOCK_MONOTONIC, &ts2); float allsec = (ts2.tv_sec – ts1.tv_sec) + (ts2.tv_nsec – ts1.tv_nsec) / 1000000000.0; float fps = frame_cnt / allsec; printf(“%f FPS
“, fps); frame_cnt = 0; clock_gettime(CLOCK_MONOTONIC, &ts1); } usleep(1000); } munmap(fb_screenshot, scr_sz); close(fd_scr); close_gpio(); printf(“fin
“); return 0;
}Сборка:pi@raspberrypi ~ $ gcc -o lcd LPH9157-2_RPI.c -lbcm2835 -lrt -std=gnu99Запуск:pi@raspberrypi ~ $ sudo ./lcd -i
pi@raspberrypi ~ $ sudo ./lcd -d -s
параметры: -i — первичная инициализация (дёргаем хардварный reset) -s — включить сглаживание -d — динамический fps (одинаковые кадры пропускаются — экономит CPU)
Результат
Источник: https://habr.com/post/251629/
1Спам44 Андрей (24.12.2014 22:26)lph9157-2сегодня смакетировал только мегу с дисплеем – не работает. |
1Спам42 Андрей (24.12.2014 09:42)Обидно, не нашёл я этой надписи… |
1Спам43 Artur21 (24.12.2014 17:37)fчто написано на обороте? LPH88? |
0Спам40 Андрей (23.12.2014 17:35)Подскажите, плз. Есть Siemens ME75. C его дисплее работать будит, если ему 2,9в подать вместо 5?Или это в прошивке надо всё переделывать? |
41 Адвансед (24.12.2014 06:30)работать будет, только смотрите чтобыдисплей был с маркировкой LS020 – другие не работают |
0Спам39 Artur21 (17.12.2014 15:34)Собирал по первой печатке, все работает! Жаль что второй вариант платы добавили позже… |
0Спам38 sergej (16.12.2014 22:43)огромное спасибо за конструкцию, пытаюсь повторить в реалии. |
37 Адвансед6476 (27.10.2014 22:06)Есть две собранные платы осциллографа, полностью рабочие, как на фотографиях, собраны по новой версии печаткию отправлю по почте, 500 рублей за плату + ваша пересылка.полный комплект, аккумулятор, дисплей, все все… кроме корпуса |
36 Адвансед6476 (27.10.2014 17:04)Внимание! Добавил новую версию печатной платы, подробности в конце статьи. Фотографии там же. |
35 Cazykeril (25.10.2014 07:24)был в отпуске, фотографии постараюсь как можно быстрее выложить |
0Спам33 Cazykeril (02.10.2014 20:57)Есть ли возможность получить исходник программы? Не хватает шкалы для понимания измерений) и вопрос при включении режима ас/dc шкала улетает в неизвестность ))) |
34 Адвансед (02.10.2014 22:11)исходника к сожалению нет, данный проект был скачен и сохранен на ПК лет 5 назад на каком то ресурсе, который уже не существует… |
1Спам30 Artur21 (27.09.2014 20:34)Кварц на 16 МГц, если контроллер не читается при правильно зашитых фузах, значит кондеры неверные… Или кварц проблемный. |
0Спам31 Cazykeril (27.09.2014 21:28)Спасибо) уже нашел причину, да кондеры не те) без операционника проверить полную работоспособность нет возможности, а и не могу понять как по этой осциллограмме без шкалы определить величину измеряемого параметра) |
Источник: http://cxema21.ru/publ/mikrokontrollery/izmeritelnye_ustrojstva/oscillograf_na_atmega8_i_lcd_ls020_ot_siemens/14-2-0-222
Работа с графическим дисплеем на базе PCD8544 — DRIVE2
Популярные в своё время сотовые телефоны фирмы Nokia, такие модели, как 3210 3310 3315 3330 3350 3410 5110 5120 5130 5160 6150 6210, обладали монохромными графическими дисплеями, с экраном 84×48 точек, на базе контроллера PCD8544.
Времена этих телефонов прошли, но дисплеи не канули в Лету, они оказались чрезвычайно удобным и дешёвым вариантом для вывода графической и текстовой информации, при использовании в сочетании с микроконтроллерами.
Сейчас на ebay можно за порядка 100 рублей (вместе с доставкой)купить такой дисплей, установленный на печатную плату 45х45мм, которая также обеспечивает подсветку.
Модуль с дисплеем от Nokia 5110 на базе чипа PCD8544
О подключении таких дисплеев, на базе контроллера PCD8544, и пойдёт речь ниже.
О контроллере
Контроллер PCD8544 разработан фирмой PHILIPS. Документацию на него можно скачать здесь
Одной из особенностей этого контроллера является то, что информация может быть только выведена на дисплей, но не считана с него.
В частности, это накладывает два ограничения:— Нет возможности узнать состояние дисплея, в т.ч. и вообще факт его присутствия программными средствами. Это требует точного соблюдения таймингов при выводе информации.
К счастью контроллер может работать на достаточно большой скорости и это не является проблемой.
— Невозможно работать с изображением в режиме «чтение-изменение-запись». Вывод сложного изображения, где потребуется совмещение разной графической информации, может быть осуществлён только с использованием внеэкранного буфера, или предварительного полного расчёта совмещения изображений.
В то же время, контроллер обеспечивает крайне низкое энергопотребление: менее 300мкА (с типичными дисплеями Nokia) в рабочем режиме, и около 1.5мкА в режиме отключения.
Контроллер имеет встроенный генератор повышенного напряжения, поэтому отдельно подводить напряжение для питания дисплея не требуется.
Сам же контроллер работает при напряжении 2,7 – 3,3 Вольта.
Подключение
Подключение модуля дисплея на базе чипа PCD8544 к МК ATmega8A
Как упоминалось выше, контроллер работает на напряжении 2,7 – 3,3 Вольта. Это значит что сопряжённый микроконтроллер должен либо работать на том же напряжении, либо же как-то согласовать уровни на выводах, например, при помощи делителей.
Кроме «земли» и «питания», к контроллеру дисплея должны идти 5 линий:
* SCLK — тактовый импульс для передачи данных.
* SDIN — передаваемые данные.
* D/C̅ — выбор типа передаваемых данных: высокий уровень — графические данные, низкий — инструкция.
* S̅C̅E̅ — выбор чипа. Передача данных осуществляется при низком уровне на этой линии. При высоком уровне данные игнорируются.
* R̅E̅S̅ — сброс. При низком уровне происходит аппаратный сброс контроллера.
Поскольку, согласно спецификации (см п.8.1) аппаратный сброс является необходимым для инициализации дисплея, линия R̅E̅S̅ также должна быть подключена.
В принципе, линия S̅C̅E̅ может быть притянута постоянно к земле, но в этом случае, если по какой либо причине контроллер дисплея потерял синхронизацию с МК, это никак не удастся обнаружить. При подключении к МК, рекомендую притягивать эту линию к высокому уровню подтягивающим резистором 100-500кОм, чтобы исключить реакцию контроллера на помехи, пока МК находится в состоянии сброса.
Обратная сторона модуля
Передача осуществляется по протоколу SPI, но только в одном направлении. При работе с микроконтроллерами AVR, удобно использовать USART в режиме SPI-master, когда включен только передатчик. Режим SPI-3 (CPHA=1, CPOL=1).
Это значит, что пока обмен отсутствует, на линии SCLK должен присутствовать высокий уровень, а чтение данных с линии SDIN контроллер осуществляет по нарастающему фронту на линии SCLK в течение 100нс.
При этом они должны быть выставлены минимум за 100 нс до нарастания фронта. Передача осуществляется по 8 бит, сначала старший.
Уровень на линии D/C̅ определяет, как трактовать полученные данные. Высокий уровень означает, что переданные данные должны быть выведены на дисплей, низкий уровень – что передана команда.
Контроллер читает значение на этой линии вместе с последним (младшим) битом каждого переданного байта данных. При использовании асинхронной аппаратной передачи с этим могут возникнуть трудности.
Перед установкой уровня необходимо дождаться завершения передачи предыдущего байта.
Максимальная частота, на которой может осуществляться обмен с PCD8544 – 4 МГц. При программном формировании импульсов это, обычно не является проблемой, но при использовании аппаратной передачи, в случае если частота работы МК превышает 8МГц, следует ограничить максимальную скорость передачи.
Кроме линий передачи данных, на модуле с дисплеем обычно присутствует вход управления подсветкой, соединённый с катодом светодиодов. Аноды же через ограничивающие резисторы подключены к линии питания.
Для постоянно работающей подсветки можно данный вход подключить напрямую, или через резистор к «земле». Для управления от МК подсветка может быть подключена через транзистор.
Поскольку подсветка потребляет менее 20мА, при подключении к МК AVR возможно также подключать её напрямую к выводу МК.
Команды контроллера
См. раздел 8 спецификации
Команды передаются контроллеру дисплея, когда на линии D/C̅ низкий уровень.
Контроллер работает с двумя наборами команд: обычным и расширенным.
Команда 00100PVH присутствует в обоих наборах команд. Значение бита H определяет какой набор команд будет использоваться: 0 – обычный, 1 – расширенный. Установленный бит P означает режим отключения (power-down). V – выбирает режим адресации: 1 – вертикальная, 0 – горизонтальная.
Обычный набор команд
Обычный набор команд выбирается после передачи 00100PV0 (см. выше)
В нём присутствуют команды:
Команда 00001D0E — выбирает режим работы дисплея. E – признак инверсии изображения. D – признак вывода изображения. Если D = 0, дисплей либо полностью очищен (E = 0), либо полностью чёрный (E = 1)
Команда 01000yyy, или 0x40 + y — выбор номера строки (страницы) на которую выводится изображение. Где y = 0 – самая верхняя строка, 5 – самая нижняя. Строка имеет высоту 8 пикслей.
Команда 1xxxxxxx, или 0x80 + x — выбор горизонтальной позиции в текущей строке, куда будет выводиться изображение. Где x = 0 – самая левая позиции, 83 – самая правая.
Расширенный набор команд
Расширенный набор команд выбирается после передачи 00100PV1 (см. выше)
В нём присутствуют команды:
Команда 000001tt, или 0x04 + t — выбор одного из четырёх режимов температурной коррекции. В зависимости от режима будет по-разному изменяться напряжение дисплея в зависимости от температуры.
Команда 00010bbb, или 0x10 + b — выбор одного из восьми режимов расчёта смещения уровней для управления LCD. Для обычных дисплеев от Nokia рекомендуется режим 0001011, или 0x13
Команда 1vvvvvvv, или 0x80 + v — выбор напряжения на генераторе повышенного напряжения для LCD. При v = 0 генератор отключен. Выходное напряжение рассчитывается по формуле (см. спецификацию п.8.9): Vlcd = 3.06 В + v * 0.06 В.
В зависимости от выбора способа коррекции напряжения, это значение изменяется в зависимости от температуры. Чтобы не повредить дисплей при низких температурах, рекомендуется чтобы это значение не превышало 8.5 Вольт, т.е. v
Источник: https://www.drive2.ru/b/1268120/
Разбираемся с LCD экраном LPH9157-2 от Siemens C75/ME75
Внятной документации на этот экран я не нашел поэтому пришлось разбираться с тем что есть и экспериментировать. В качестве управляющего устройства я использовал Raspberry PI. Так-же была написана программа позволяющая превратить этот экран в мини-монитор.
Данный дисплей имеет разрешение 135 x 176 пикселей и даёт возможность работать с тремя цветовыми палитрами 16(6-5-6), 12(4-4-4) и 8(3-3-2) бит.Тут всё просто, экран питается напряжением 2,9 вольт, подсветка (LED±) запитывается отдельно напряжением примерно 12 вольт(я использовал батарею аккумуляторов соединённую с подсветкой через резистор на 510 Ом).
Pin description# | Name | Function |
1 | RS | Low=CMD, High=DATA |
2 | ~RST | Reset input, active low |
3 | ~CS | Chip select, active low |
4 | SYNC | External frame synchorization input, unused by default |
5 | CLK | SPI Clock-in signal (High-to-Low) |
6 | DATA | SPI Data-in signal (MSB first) |
7 | VCC | Power supply, normally 2.9V (I tested with 3.3V) |
8 | GND | Ground |
9 | LED+ | Backlight voltage, approx. 12V (depends on required current) |
10 | LED- | Backlight common pin |
Как можно заметить экран управляется через интерфейс SPI (контакты CS/CLK/DAT(MOSI)), предположительно это лишь половина интерфейса так как отсутствует контакт MISO, следовательно писать данные в экран мы можем, а вот читать — нет(здесь следует упомянуть что SPI может работать в двунаправленном режиме с использованием одного провода (MIMO) но так как отсутствует какие либо команды чтения данных из экрана будем считать что этот режим экраном не используется).
И перед тем как переходить непосредственно к управлению экраном надо бы этот экран к чему-нибудь подключить. В моём случае это будет Raspberry Pi. Контакты SPI экрана подключены к соответствующим им контактам SPI «малины», RS и RST к GPIO_17 и GPIO_27 соответственно. Данное подключение актуально для RPI Revision-2, если у вас иная модель то названия и номера контактов GPIO могут отличаться.
Заморачиваться с разъёмом подключения экрана я не стал и просто подпаялся к выводам проводом МГТФ. Экран в данном подключении питается от 3.3В, а не от 2.9 как в описании.Вот так выглядит вся схема в сборе
Экран управляется достаточно просто — путём посылки по SPI команд и данных. Отличить одни от других экрану помогает состояние пина RS где высокий уровень(лог. 1) означает передачу данных, а низкий(лог. 0) передачу команд. При передаче используется тупоконечный(big-ending) порядок байт.
Список команд:
- CMD_RESET 0x01 — программный сброс
- CMD_MEMORY_ACCESS_CONTROL 0x36 — установка направления заполнения области дисплея, имеет однобайтовый аргумент 0bVHRXXXXX, гдеV — заполнение по вертикали (0 — сверху-вниз, 1 — снизу-вверх),H — заполнение по горизонтали (0 — слева-направо, 1 — справа-налево),R — меняются местами строки и столбцы (при этом заполнение остается сверху-вниз, слева-направо))
- CMD_WAKEUP 0x11 — выход из спящего режима
- CMD_PALETTE 0x3A — установка цветовой палитры 8(0x02), 12(0x03) и 16(0x05) бит
- CMD_ENABLE 0x29 — включение дисплея
- CMD_SET_X 0x2A — задаем область рисования по X
- CMD_SET_Y 0x2B — задаем область рисования по Y
- CMD_START_WRITE 0x2C — начало записи в видеопамять
Работа экрана была проверена во всех 3х цветовых режимах но, дабы не захламлять исходник, далее я буду рассматривать только 16-битный. Во всех остальных режимах работа экрана не отличается, за исключением, разве что 12-битного — в нём на 2 пикселя приходится 3 байта, а если нужно вывести лишь одну точку то посылается 2 байта(4 младших бита последнего экраном игнорируются).
Для доступа к GPIO «малины» была использована библиотека bcm2835.
int init_gpio(){ if (!bcm2835_init()) return 0; bcm2835_spi_begin(); bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_MSBFIRST);// CPOL = 0, CPHA = 0, Clock idle low, data is clocked in on rising edge, output data (change) on falling edge bcm2835_spi_setDataMode(BCM2835_SPI_MODE0);// в телефоне экран работает на частоте SPI в 13 МГц// поэтому небольшое превышение по частоте ему не повредит// хотя у меня он продолжал работать и при вдвое большей частоте (30 МГц) bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_16); ///
}
void send_cmd(char cmd){ bcm2835_gpio_write(LCD_RS, RS_CMD); // следующий байт – команда bcm2835_spi_transfer(cmd);}void send_data(char data){ bcm2835_gpio_write(LCD_RS, RS_DATA); // следующий байт – данные bcm2835_spi_transfer(data);}
void set_draw_area(char x1, char y1, char x2, char y2){ send_cmd(CMD_SET_X); send_data(x1); send_data(x2); send_cmd(CMD_SET_Y); send_data(y1); send_data(y2);
}
В результате экспериментов с экраном выяснилось что необязательно задавать область перед выводом каждого кадра, достаточно задать её лишь единожды и послав команду начала записи просто гнать по SPI последовательность кадров непрерывным потоком.
void draw_start(){ send_cmd(CMD_START_WRITE); bcm2835_gpio_write(LCD_RS, RS_DATA);}void send_draw_data(char* data, int size){ bcm2835_spi_transfern(data, size);
}
В процессе инициализации экрана обнаружилась досадная вещь — для запуска необходимо передёрнуть RESET экрана, а вот последующие манипуляции данным выводом приводят экран в ступор и он перестаёт реагировать на внешние воздействия. Приходится сбрасывать его по питанию. Это необходимо учесть при разработке программы дабы процедура аппаратного сброса выполнялась лишь единожды.
void reset_LCD(){ // аппаратный сброс bcm2835_gpio_write(LCD_RESET, LOW); bcm2835_delay(50); bcm2835_gpio_write(LCD_RESET, HIGH); bcm2835_delay(50); // программный сброс send_cmd(CMD_RESET);}void init_LCD(){ reset_LCD(); send_cmd(CMD_MEMORY_ACCESS_CONTROL); send_data(0b00000000); send_cmd(CMD_WAKEUP); bcm2835_delay(20); send_cmd(CMD_PALETTE); send_data(_16_BIT_COLOR); bcm2835_delay(20); send_cmd(CMD_ENABLE);
}
Это была подготовка, а теперь самое вкусное — попробуем вывести на экран 16-битную картинку. Первый блин как известно — комом, после запуска программы я получил довольно странное изображение, оказалось — неверный порядок байт, после исправления всё заработало.
int main(int argc, char **argv){ if (!init_gpio()) return 1; init_LCD(); set_draw_area(0, 0, SCREEN_WIDTH – 1, SCREEN_HEIGHT – 1); draw_start(); uint16_t screen[SCREEN_HEIGHT][SCREEN_WIDTH]; FILE* f_scr = fopen(“test.bmp”, “r”); fseek(f_scr, 0x42, SEEK_SET); // skip bmp header fread(&screen, 1, SCREEN_HEIGHT * SCREEN_WIDTH * 2/*16bit*/, f_scr); fclose(f_scr); // change byte order for(int x = 0; x > 8) | (screen[y][x] 176×132 малоинформативен, для фреймбуфера было установлено разрешение 320×240, это можно сделать правкой config.txt на FAT разделе «малиновой» флешки.
framebuffer_width=320
framebuffer_height=240
После этого изображение всё равно жмётся с использованием примитивной интерполяции, но результат уже можно назвать приемлемым. Так-же был добавлен пропуск одинаковых кадров для экономии CPU.Исходник LPH9157-2_RPI.c
#include #include #include #include #include #include #include // соответствия контактов GPIO и LCD#define LCD_RS RPI_V2_GPIO_P1_11#define LCD_RESET RPI_V2_GPIO_P1_13#define RS_CMD 0#define RS_DATA 1#define CMD_RESET 0x01#define CMD_MEMORY_ACCESS_CONTROL 0x36 // Memory Access Control#define CMD_WAKEUP 0x11 // Выход из спящего режима#define CMD_PALETTE 0x3A // Установка цветовой палитры#define CMD_ENABLE 0x29 //Включение дисплея#define CMD_SET_X 0x2A // задаем область по X#define CMD_SET_Y 0x2B // задаем область по Y#define CMD_START_WRITE 0x2C // начало записи в память#define _8_BIT_COLOR 0x02#define _12_BIT_COLOR 0x03#define _16_BIT_COLOR 0x05#define SCREEN_WIDTH 132#define SCREEN_HEIGHT 176int init_gpio(){ if (!bcm2835_init()) return 0; bcm2835_spi_begin(); bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_MSBFIRST); bcm2835_spi_setDataMode(BCM2835_SPI_MODE0); /// CPOL = 0, CPHA = 0, Clock idle low, /// data is clocked in on rising edge, /// output data (change) on falling edge bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_16); ///= 0) && (fb_x + 1 = 0) && (fb_y + 1 > 1); /// ^thank you habr => http://ift.tt/1vIjXyi } } } screen[y][SCREEN_WIDTH – 1 – x] = (px > 8); } send_draw_data((char*)&screen[0][0], sizeof(screen)); /// calc fps frame_cnt++; if(frame_cnt >= 100) { clock_gettime(CLOCK_MONOTONIC, &ts2); float allsec = (ts2.tv_sec – ts1.tv_sec) + (ts2.tv_nsec – ts1.tv_nsec) / 1000000000.0; float fps = frame_cnt / allsec; printf(“%f FPS
“, fps); frame_cnt = 0; clock_gettime(CLOCK_MONOTONIC, &ts1); } usleep(1000); } munmap(fb_screenshot, scr_sz); close(fd_scr); close_gpio(); printf(“fin
“); return 0;
}
Сборка:
pi@raspberrypi ~ $ gcc -o lcd LPH9157-2_RPI.c -lbcm2835 -lrt -std=gnu99
Запуск:
pi@raspberrypi ~ $ sudo ./lcd -ipi@raspberrypi ~ $ sudo ./lcd -d -s
параметры:-i — первичная инициализация (дёргаем хардварный reset)-s — включить сглаживание-d — динамический fps (одинаковые кадры пропускаются — экономит CPU)
This entry passed through the Full-Text RSS service – if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.
Источник: http://habrparser.blogspot.com/2015/02/lcd-lph9157-2-siemens-c75me75.html
Ардуино: вывод текста на ЖК дисплей 1602
Все давно привыкли, что у каждого электронного устройства есть экран, с помощью которого оно дает человеку всякую полезную информацию. MP3-плеер показывает название играемого трека, пульт квадрокоптера отображает полетную телеметрию, даже стиральная машина выводит на дисплей время до конца стирки, а на смартфоне вообще размещается целый рабочий стол персонального компьютера!
Скорее всего, вашему очередному устройству тоже не помешает какой-нибудь небольшой дисплейчик
Источник: http://robotclass.ru/tutorials/arduino-lcd1602/
Розбираємося з LCD екраном LPH9157-2 від Siemens C75/ME75
Виразної документації на цей екран я не знайшов тому довелося розбиратися з тим що є і експериментувати. В якості керуючого пристрою я використовував Raspberry PI. Так-же була написана програма, що дозволяє перетворити цей екран міні-монітор.
Опис
Цей дисплей має дозвіл 135 x 176 пікселів і дає можливість працювати з трьома колірними палітрами 16(6-5-6), 12(4-4-4) та 8(3-3-2) біт.
Терморегулятори і підключення
Тут все просто, екран живиться напругою 2,9 вольт, підсвічування (LED±) записується окремо напругою приблизно 12 вольт(я використовував батарею акумуляторів з'єднану з підсвічуванням через резистор на 510 Ом).
Pin description# | Name | Function | 1 | RS | Low=CMD, High=DATA | 2 | ~RST | Reset input, active low | 3 | ~CS | Chip select, active low | 4 | SYNC | External frame synchorization input, unused by default | 5 | CLK | SPI Clock-in signal (High-to-Low) | 6 | DATA | SPI Data-in signal (MSB first) | 7 | VCC | Power supply, normally 2.9 V (I tested with 3.3 V) | 8 | GND | Ground | 9 | LED+ | Backlight voltage, approx. 12V (depends on required current) | 10 | LED- | Backlight common pin |
Як можна помітити екран управляється через інтерфейс SPI (контакти CS/CLK/DAT(MOSI)), імовірно це лише половина інтерфейсу так як відсутній контакт MISO, отже писати дані в екран ми можемо, а от читати — ні(тут слід згадати що SPI може працювати в двонаправленому режимі з використанням одного проводу (MIMO) але так як відсутня якісь команди читання даних з екрану будемо вважати, що цей режим екраном не використовується).
І перед тим як переходити безпосередньо до управління екраном треба б цей екран до чого-небудь підключити. У моєму випадку це буде Raspberry Pi. Контакти SPI екрану підключені до відповідних їм контактам SPI «малини», RS і RST до GPIO_17 і GPIO_27 відповідно. Дане підключення актуально для RPI Revision-2, якщо у вас інша модель назви і номери контактів GPIO можуть відрізнятися.
Морочитися з роз'ємом підключення екрана я не став і просто подпаялся до висновків проводом МГТФ. Екран в даному підключенні живиться від 3.3 В, а не від 2.9 в описі. Ось так виглядає вся схема в зборі
Команди управління екраном
Екран управляється досить просто — шляхом посилки SPI команд і даних. Відрізнити одні від інших екрану допомагає стан піна RS де високий рівень(лог. 1) означає передачу даних, а низький(лог. 0) передачу команд. При передачі використовується тупоконечный(big-ending) порядок байт.
Список команд:
- CMD_RESET 0x01 — програмний скидання
- CMD_MEMORY_ACCESS_CONTROL 0x36 — установка напряму заповнення області дисплея, має однобайтний аргумент 0bVHRXXXXX, де V — заповнення по вертикалі (0 — зверху-вниз, 1 — знизу-вгору), H — заповнення по горизонталі (0 — зліва-направо, 1 — праворуч-ліворуч),
R — міняються місцями рядки і стовпці (при цьому заповнення залишається зверху-вниз, зліва-направо))
- CMD_WAKEUP 0x11 — вихід із сплячого режиму
- CMD_PALETTE 0x3A — установка колірної палітри 8(0x02), 12(0x03) і 16(0x05) біт
- CMD_ENABLE 0x29 — включення дисплея
- CMD_SET_X 0x2A — задаємо область малювання по X
- CMD_SET_Y 0x2B — задаємо область малювання по Y
- CMD_START_WRITE 0x2C — початок запису в відеопам'ять
Код
Робота екрану була перевірена у всіх 3х колірних режимах але, щоб не захаращувати вихідний, далі я буду розглядати тільки 16-бітний.
У всіх інших режимах робота екрану не відрізняється, за винятком, хіба що 12-бітного — в ньому на 2 пікселя припадає 3 байти, а якщо потрібно вивести лише одну точку то надсилається 2 байти(4 молодших біта останнього екраном ігноруються).
Для доступу до GPIO «малини» була використана бібліотека bcm2835.
Початкова ініціалізація GPIO
int init_gpio() { if (!bcm2835_init()) return 0; bcm2835_spi_begin(); bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_MSBFIRST); // CPOL = 0, CPHA = 0, Clock idle low, data is clocked in on rising edge, output data (change) falling on edge bcm2835_spi_setDataMode(BCM2835_SPI_MODE0); // в телефоні екран працює на частоті SPI в 13 МГц // тому невелике перевищення по частоті йому не зашкодить // хоча у мене він продовжував працювати і при вдвічі більшій частоті (30 МГц) bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_16); ///
Декілька допоміжних функцій
void send_cmd(char cmd) { bcm2835_gpio_write(LCD_RS, RS_CMD); // наступний байт – команда bcm2835_spi_transfer(cmd); } void send_data(char data) { bcm2835_gpio_write(LCD_RS, RS_DATA); // наступний байт – дані bcm2835_spi_transfer(data); }
Завдання області малювання
void set_draw_area(char x1, char y1, char x2, char y2) { send_cmd(CMD_SET_X); send_data(x1); send_data(x2); send_cmd(CMD_SET_Y); send_data(y1); send_data(y2); }В результаті експериментів з екраном з'ясувалося що необов'язково ставити область перед виведенням кожного кадру, достатньо задати її лише один раз і пославши команду початку запису просто гнати по SPI послідовність кадрів безперервним потоком.
Підготовка до виведення та передача даних
void draw_start() { send_cmd(CMD_START_WRITE); bcm2835_gpio_write(LCD_RS, RS_DATA); } void send_draw_data(char* data, int size) { bcm2835_spi_transfern(data, size); }В процесі ініціалізації екрану виявилася прикра річ — для запуску необхідно пересмикнути RESET екрану, а от подальші маніпуляції даними висновком призводять екран в ступор і він перестає реагувати на зовнішні впливи. Доводиться скидати його з харчування. Це необхідно врахувати при розробці програми щоб процедура апаратного скидання виконувалася лише один раз.
Ініціалізація екрану
void reset_LCD() { // апаратний скидання bcm2835_gpio_write(LCD_RESET, LOW); bcm2835_delay(50); bcm2835_gpio_write(LCD_RESET, HIGH); bcm2835_delay(50); // програмний скидання send_cmd(CMD_RESET); } void init_LCD() { reset_LCD(); send_cmd(CMD_MEMORY_ACCESS_CONTROL); send_data(0b00000000); send_cmd(CMD_WAKEUP); bcm2835_delay(20); send_cmd(CMD_PALETTE); send_data(_16_BIT_COLOR); bcm2835_delay(20); send_cmd(CMD_ENABLE); }Це була підготовка, а тепер найсмачніше — спробуємо вивести на екран 16-бітну картинку. Перший млинець, як відомо, грудкою, після запуску програми я отримав досить дивне зображення, виявилося — неправильний порядок байт, після виправлення все запрацювало.
Код
int main(int argc, char **argv) { if (!init_gpio()) return 1; init_LCD(); set_draw_area(0, 0, SCREEN_WIDTH – 1, SCREEN_HEIGHT – 1); draw_start(); uint16_t screen[SCREEN_HEIGHT][SCREEN_WIDTH]; FILE* f_scr = fopen(“test.
bmp”, “r”); fseek(f_scr, 0x42, SEEK_SET); // skip bmp header fread(&screen, 1, SCREEN_HEIGHT * SCREEN_WIDTH * 2/*16bit*/, f_scr); fclose(f_scr); // change byte order for(int x = 0; x > 8) | (screen[y][x] 176×132 малоінформативний, для фреймбуфер було встановлено дозвіл 320×240, це можна зробити правкою config.txt на FAT розділі «малинової» флешки.framebuffer_width=320 framebuffer_height=240Після цього зображення все одно тулиться з використанням примітивної інтерполяції, але результат вже можна назвати прийнятним. Так-же був доданий пропуск однакових кадрів для економії CPU.
Ісходник LPH9157-2_RPI.c
#include #include #include #include #include #include #include // відповідності контактів GPIO та LCD #define LCD_RS RPI_V2_GPIO_P1_11 #define LCD_RESET RPI_V2_GPIO_P1_13 #define RS_CMD 0 #define RS_DATA 1 #define CMD_RESET 0x01 #define CMD_MEMORY_ACCESS_CONTROL 0x36 // Memory Access Control #define CMD_WAKEUP 0x11 // Вихід із сплячого режиму #define CMD_PALETTE 0x3A // Установка колірної палітри #define CMD_ENABLE 0x29 //Включення дисплея #define CMD_SET_X 0x2A // задаємо область по X #define CMD_SET_Y 0x2B // задаємо область по Y #define CMD_START_WRITE 0x2C // початок запису в пам'ять #define _8_BIT_COLOR 0x02 #define _12_BIT_COLOR 0x03 #define _16_BIT_COLOR 0x05 #define SCREEN_WIDTH 132 #define SCREEN_HEIGHT 176 int init_gpio() { if (!bcm2835_init()) return 0; bcm2835_spi_begin(); bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_MSBFIRST); bcm2835_spi_setDataMode(BCM2835_SPI_MODE0); /// CPOL = 0, CPHA = 0, Clock idle low, /// data is clocked in on rising edge, /// output data (change) falling on edge bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_16); ///= 0) && (fb_x + 1 = 0) && (fb_y + 1 > 1); /// ^thank you habr => http://habr.ru/p/128773/ } } } screen[y][SCREEN_WIDTH – 1 – x] = (px > 8); } send_draw_data((char*)&screen[0][0], sizeof(screen)); /// calc fps frame_cnt++; if(frame_cnt >= 100) { clock_gettime(CLOCK_MONOTONIC, &ts2); float allsec = (ts2.tv_sec – ts1.tv_sec) + (ts2.tv_nsec – ts1.tv_nsec) / 1000000000.0; float fps = frame_cnt / allsec; printf(“%f FPS
“, fps); frame_cnt = 0; clock_gettime(CLOCK_MONOTONIC, &ts1); } usleep(1000); } munmap(fb_screenshot, scr_sz); close(fd_scr); close_gpio(); printf(“fin
“); return 0; }Збірка:pi@raspberrypi ~ $ gcc-o lcd LPH9157-2_RPI.c-lbcm2835-lrt-std=gnu99Запуск:pi@raspberrypi ~ $ sudo ./lcd-i pi@raspberrypi ~ $ sudo ./lcd-d-s параметри: -i — первинна ініціалізація (смикаємо хардварный reset) -s — увімкнути згладжування -d — динамічний fps (однакові кадри пропускаються — економить CPU)
Результат
Джерело: Хабрахабр
Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.
Источник: http://it-ua.info/news/2015/03/07/rozbiramosya-z-lcd-ekranom-lph9157-2-vd-siemens-c75-me75.html