Запуск индикатора OLED WEX025664 на библиотеке u8glib |
![]() |
Добавил(а) microsin | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Эта статья посвящена быстрому старту в использовании OLED-индикатора WEX025664CLPP3N00000 компании Winstar на примере подключения к микроконтроллеру AVR через интерфейс SPI. Использовалась библиотека u8glib [1]. Индикатор основан на контроллере SSD1322 [6]. В Интернете нашел даташит с описанием системы команд, библиотеку u8glib, где была поддержка этого чипа на примере индикатора NHD-3.12-25664 OLED Display. Оказалось, что код для этого индикатора подходит для управления индикатором WEX025664CLPP3N00000. [Подключение индикатора WEX025664] В таблице приведена цоколевка коннектора индикатора WEX025664.
Примечание *: насколько я понял, напряжение VDD и напряжение лог. 1 зависит от версии индикатора. Есть индикаторы с 3-вольтовым драйвером, как например WEX025664CLPP3N00000 (выделенная жирным шрифтом цифра 3 обозначает 3-вольтовую версию драйвера), а есть с 5-вольтовым. Мне попался 3-вольтовый индикатор. Для управления индикатором была выбрана макетная плата AVR-USB162, потому что микроконтроллер AT90USB162, установленный на ней, содержит встроенный маломощный стабилизатор напряжения 3.3V, и логические уровни GPIO и SPI микроконтроллера можно переключать перемычкой J3 (5V или 3.3V). Схема подключения к макетной плате AVR-USB162 (микроконтроллер AT90USB162): R1, R3 и соответствующие конденсаторы нужны для фильтрации напряжений питания индикатора. R2 служит для установки опорного тока системы настройки яркости индикатора (см. даташиты на индикатор [4]), его номинал не критичен. Интерфейс индикатора переключен выводами BS0, BS1 в режим SPI, и сигналы данных D0, D1 заведены на сигналы тактов и данных аппаратного интерфейса SPI микроконтроллера AT90USB162. Для питания индикатора необходим дополнительный источник питания напряжением +12..15V и максимальным током 60 мА. Напряжение питания индикатора +3.3V получено с внутреннего стабилизатора чипа AT90USB162 (перемычку J3 макетной платы AVR-USB162 следует установить в положение 2-3). [Использование библиотеки u8glib] Скачайте и установите библиотеку u8glib (см. ссылки [1, 2]). Установка заключается в распаковке папки u8glib из архива в корневой каталог проекта и добавлении всех файлов из каталога src в проект. В пути поиска подключаемых файлов нужно добавить каталог src, потому что там находится заголовочный файл библиотеки u8g.h. Ссылка на домашнюю страничку проекта: http://code.google.com/p/u8glib/ (или см. ключевые слова для поиска ссылок [1, 2]). Как подключить библиотеку u8glib к проекту: 1. Загрузите архив u8glib_avr_vX.XX.zip Для AVR Studio 4 нужно настроить дополнительные опции, пожалуйста см. ссылку: Пошаговые инструкции для Atmel Studio 6: Обычно все проекты для AVR, созданные как для AVR Studio 4, так и для Atmel Studio, так и для Eclipse, так и для MS Visual Studio (да-да, Вы не ослышались, программы для AVR можно разрабатывать и под управлением среды Visual Studio, см. [5]) компилируют исходный код с использованием тулчейна avr-libc (сборка WinAVR или сборка компании Atmel). Это означает использование для проекта makefile и утилиты make. Чтобы добавить в проект компиляцию модулей библиотеки U8glib, нужно соответствующим образом отредактировать makefile проекта. Вот пример такого makefile (этот файл взят из библиотеки LUFA, пример устройства USB из каталога Demos\Device\ClassDriver\GenericHID\): MCU = at90usb162 ARCH = AVR8 #BOARD = USBKEY
BOARD = MICROSIN162 F_CPU = 8000000 F_USB = $(F_CPU) OPTIMIZATION = s TARGET = GenericHID #SRC = $(TARGET).c Descriptors.c $(LUFA_SRC_USB) $(LUFA_SRC_USBCLASS)
SRC = $(wildcard *.c) $(wildcard u8glib/src/*.c) $(LUFA_SRC_USB) $(LUFA_SRC_USBCLASS) LUFA_PATH = c:/asm/lufa-LUFA-140928/LUFA CC_FLAGS = -DUSE_LUFA_CONFIG_HEADER -IConfig/ -Iu8glib/src/ -ffunction-sections -fdata-sections LD_FLAGS = # Default target
all: # Include LUFA build script makefiles
include $(LUFA_PATH)/Build/lufa_core.mk
include $(LUFA_PATH)/Build/lufa_sources.mk
include $(LUFA_PATH)/Build/lufa_build.mk
include $(LUFA_PATH)/Build/lufa_cppcheck.mk
include $(LUFA_PATH)/Build/lufa_doxygen.mk
include $(LUFA_PATH)/Build/lufa_dfu.mk
include $(LUFA_PATH)/Build/lufa_hid.mk
include $(LUFA_PATH)/Build/lufa_avrdude.mk
include $(LUFA_PATH)/Build/lufa_atprogram.mk
Здесь в макроопределение SRC добавлена компиляция файлов u8glib с помощью директивы $(wildcard u8glib/src/*.c). Пути поиска заголовочных файлов обновлены путем добавления к макроопределению CC_FLAGS опции -Iu8glib/src/. /*-----------------------------------------------------------------------
Простой пример запуска индикатора WEX025664BLPP3N00000, подключенного
к макетной плате AVR-USB162.
-----------------------------------------------------------------------*/
#include < avr/io.h >
#include "u8g.h"
//Сигналы, которые идут на OLED-индикатор WEX025664BLPP3N00000
#define DC PB4 //выход, Data/Command Control. #define _CS PB0 //выход, сигнал выборки (лог. 0). //Сигналы SPI (для передачи данных в OLED-индикатор WEX025664BLPP3N00000)
#define _SS PB0
#define MOSI PB2
#define SCK PB1
u8g_t u8g;
static void draw(void) { u8g_SetFont(&u8g, u8g_font_6x10); u8g_DrawStr(&u8g, 0, 15, "Hello World!"); } static void InitOLED (void) { // Настроить PB4(/SS), PB5(MOSI), PB7(SCK) как выходы: DDRB |= (1 << _SS)|(1 << MOSI)|(1 << SCK); //Инициализация индикатора: u8g_InitHWSPI(&u8g, &u8g_dev_ssd1322_nhd31oled_bw_hw_spi, PN(1, _CS), PN(1, DC), U8G_PIN_NONE); } int main(void) { SetupHardware(); InitOLED(); for (;;) { draw(); u8g_FirstPage(&u8g); do { draw(); } while ( u8g_NextPage(&u8g) ); u8g_Delay(100); } } Пример вывода текста "Hello World!" я взял из файла u8glib\examples\hello_world\hello_world.c библиотеки. Изначально этот код был рассчитан на микроконтроллер ATmega88, я запустил его на микроконтроллере AT90USB162, отредактировав опции makefile и поправив код модуля u8g_com_atmega_hw_spi.c. Пояснения к коду: 1. Инициализация индикатора происходит в процедуре InitOLED с помощью вызова функции u8g_InitHWSPI. Эта функция инициализирует аппаратный интерфейс SPI для доступа к индикатору. Функция принимает следующие параметры: *u8g указатель на глобальную переменную, где хранятся текущие данные индикатора. *dev указатель на предопределенный тип индикатора. Все возможные типы перечислены в заголовочном файле u8glib\src\u8g.h, Вам нужно выбрать один из этих типов, который подходит к используемому индикатору. PN(1, _CS) макрос, который задает ножку порта микроконтроллера для выборки индикатора. Первый параметр макроса (1) указывает PORTB (0 соответствует PORTA, 1 соответствует PORTB, 2 соответствует PORTD и т. д.), а второй параметр (_CS) задает номер разряда используемого порта (от 0 до 7). PN(1, DC) макрос, который задает ножку порта микроконтроллера для выбора Command/Data (сигнал DC). U8G_PIN_NONE задает сигнал сброса. Это макроопределение означает, что сигнал сброса не используется. По идее тут должен быть макрос наподобие PN(1, _RES). Но на самом деле опытным путем я выяснил, что если указать сигнал сброса, то код индикатора не работает, потому что ошибочно постоянно выставляется низкий уровень сигнала сброс. 2. При компиляции могут быть ошибки, связанные с неиспользуемыми модулями кода библиотеки в каталоге src. Ненужные модули удалите. Я удалил следующие модули (это значительно ускорило компиляцию проекта): chessengine.c u8g_dev_pcd8544_84x48.c u8g_com_arduino_attiny85_hw_spi.c u8g_dev_pcf8812_96x65.c u8g_com_arduino_common.c u8g_dev_sbn1661_122x32.c u8g_com_arduino_fast_parallel.c u8g_dev_ssd1306_128x32.c u8g_com_arduino_hw_spi.c u8g_dev_ssd1306_128x64.c u8g_com_arduino_hw_usart_spi.c u8g_dev_ssd1309_128x64.c u8g_com_arduino_no_en_parallel.c u8g_dev_ssd1327_96x96_gr.c u8g_com_arduino_parallel.c u8g_dev_ssd1351_128x128.c u8g_com_arduino_port_d_wr.c u8g_dev_st7565_64128n.c u8g_com_arduino_ssd_i2c.c u8g_dev_st7565_dogm128.c u8g_com_arduino_st7920_custom.c u8g_dev_st7565_dogm132.c u8g_com_arduino_st7920_hw_spi.c u8g_dev_st7565_lm6059.c u8g_com_arduino_st7920_spi.c u8g_dev_st7565_lm6063.c u8g_com_arduino_std_sw_spi.c u8g_dev_st7565_nhd_c12832.c u8g_com_arduino_sw_spi.c u8g_dev_st7565_nhd_c12864.c u8g_com_arduino_t6963.c u8g_dev_st7687_c144mvgd.c u8g_com_arduino_uc_i2c.c u8g_dev_st7920_128x64.c u8g_com_atmega_parallel.c u8g_dev_st7920_192x32.c u8g_com_atmega_st7920_spi.c u8g_dev_st7920_202x32.c u8g_com_atmega_sw_spi.c u8g_dev_t6963_128x128.c u8g_com_i2c.c u8g_dev_t6963_128x64.c u8g_com_raspberrypi_hw_spi.c u8g_dev_t6963_240x128.c u8g_com_raspberrypi_ssd_i2c.c u8g_dev_t6963_240x64.c u8g_dev_a2_micro_printer.c u8g_dev_tls8204_84x48.c u8g_dev_ht1632.c u8g_dev_uc1601_c128032.c u8g_dev_ili9325d_320x240.c u8g_dev_uc1608_240x128.c u8g_dev_ks0108_128x64.c u8g_dev_uc1608_240x64.c u8g_dev_lc7981_160x80.c u8g_dev_uc1610_dogxl160.c u8g_dev_lc7981_240x128.c u8g_dev_uc1611_dogm240.c u8g_dev_lc7981_240x64.c u8g_dev_uc1611_dogxl240.c u8g_dev_lc7981_320x64.c u8g_dev_uc1701_dogs102.c u8g_dev_ld7032_60x32.c u8g_dev_uc1701_mini12864.c 3. При портировании кода на другие микроконтроллеры AVR возможно потребуется редактирование модуля u8g_com_atmega_hw_spi.c библиотеки. Также необходимо вручную настроить аппаратный сигнал ~SS как выход (почему так, см. [3]). Исходный код моего тестового проекта и документацию можете скачать в архиве по ссылке [4]. 4. Если у Вас индикатор, у которого размер экрана по горизонтали больше 248 точек (это как раз верно для нашего примера с индикатором WEX025664BLPP3N00000), то не забывайте о макроопределении U8G_16BIT (он находится в файле u8g.h). Если его не раскомментировать, то размер экрана уменьшится на 8 точек по горизонтали, и вместо 256 станет 248 (меньше на 4 точки слева и меньше на 4 точки справа). Если макрос U8G_16BIT определен, то затраты памяти несколько увеличатся, но зато будет доступен полный размер экрана. [Как устранить паразитную засветку] На фотографии выше Вы наверное заметили полосы засветки, которые появляются за светящимися элементами изображения. Причина в неправильной настройке выхода опорного напряжения VSL. Эта настройка делается с помощью команды 0xB4 (Display Enhancement A) контроллера SSD1322 [6]. Скорее всего, в Вашей схеме подключения внешний вывод VSL остался не подключенным. Однако почему-то в библиотеке u8glib по умолчанию применена неправильная настройка в команде 0xB4, прописанная в массиве команд установки режима u8g_dev_ssd1322_1bit_nhd_312_init_seq[] (см. модуль u8glib\src\u8g_dev_ssd1322_nhd31oled_bw.c, если у Вас индикатор работает в черно-белом режиме) или u8g_dev_ssd1322_2bit_nhd_312_init_seq[] (u8glib\src\u8g_dev_ssd1322_nhd31oled_gr.c, если используются градации серого). В первом байте команды выдается байт 0xA0 в расчете на подключенные внешние цепи к выводу VSL, но здесь ошибка, нужно исправить на 0xA2: ... U8G_ESC_ADR(0), /* режим инструкции */ 0x0b4, /* Display Enhancement A */ U8G_ESC_ADR(1), /* режим данных */ //0x0a0, это неправильно! 0x0a2, // правильная настройка 0x005|0x0fd, ...
[Как снизить энергопотребление индикатора] Ток потребления индикатора OLED почти прямо пропорционально зависит: 1. От яркости пикселей. Поэтому при программировании графики с акцентом на снижение энергопотребления нужно стараться свести к минимуму количество светящихся пикселей на картинке. Для мобильных приложений желательно применить автоматическую регулировку яркости в зависимости от внешнего освещения (по фотодатчику) - этим можно значительно улучшить экономию энергии батареи. Также ток потребления в некоторой степени зависит от настройки внутреннего тактового генератора (см. команду 0xB3 [6]). Общее правило - чем меньше частота сканирования матрицы OLED, тем меньше потери на перезарядку емкостей, и тем меньше потребление энергии. Однако эта регулировка дает незначительную экономию в сравнении с экономией, которую можно достичь управлением яркостью. Обычно частоту сканирования уменьшают до минимума, пока не станет заметным мерцание экрана. Для экономии энергии можно также временно выключать экран (команда 0xA4) и включать его при необходимости (команда 0xA5). Можно выключать напряжение питания сегментов +15V. Также имеется команда, переводящая контроллер в режим сна (0xAE), и возвращающая контроллер в рабочее состояние (0xAF). [Ссылки] 1. u8glib site:code.google.com. |