Уже сто лет в моих закромах валялся знакосинтезирующий дисплейчик от WINSTAR — WH0802A-YGH-CT, когда-то купленный как самый дешевый с целью поиграться. И вот я наконец-то извлек его из темных далей. Собственно, по этому поводу и был написан драйвер для него.
Как явствует из даташита, сей модуль собран на базе контроллера ICST7066U, система команд которого приведена там же. Уж не знаю, в какой степени он аналогичен HD44780, но четырехбитный режим тоже присутствует. Тем не менее, я решил отойти от мейнстрима и включить его в восьмибитном режиме. Управляющие выходы подключаются напрямую к порту МК (для экспериментов я использовал свою бессменную плату с ATmega48), восьмибитная шина данных — через сдвиговый регистр типа 74HC595 (DB0 — Q0, DB1 — Q1, и т.д.). Все это задефайнено в wh0802a.h:
#define LCD_PORT PORTD #define LCD_DDR DDRD #define LCD_RS (1<<PD4) //Assumed to be always '0' - no read from module //#define LCDCTL_RW #define LCD_E (1<<PD3) //Shift register signals #define LCD_SHCP (1<<PD7) #define LCD_STCP (1<<PD6) #define LCD_DSER (1<<PD5)
Из сигналов управления используется только E (enable) и RS (register select, переключатель команда/данные). RW постоянно подключен к земле — только запись. Как по мне, чем заморачиваться с чтением из дисплея, проще завести внутренний буфер, благо сам дисплей-то всего 8х2 символа.
Принцип управления прост до невозможности: сигналом RS выбираем, что писать — команду или данные, ну и пишем. Дисплей читает байт со входа по спадающему фронту сигнала E.
Команды и инициализационная последовательность описаны в даташите. Есть только одна заметная неясность — команда «Display ON/OFF control». Согласно таблице, она имеет следующий формат:
В описании же инициализации видим:
Опытным путем было установлено, что для включения дисплея и выключения всяких курсоров команда должна иметь вид 0х0С, т.е. 0000 1100. Так что, похоже, правда в таблице.
Сам драйвер минималистичен и прост, ничего лишнего. Инициализация, вывод строки, вывод числа, очистка дисплея, выбор строки, в которую писать, все с говорящими названиями и префиксом LCD_… . Отдельного упоминания, пожалуй, заслуживают только интегрированные функции преобразования числа в строку. Их две:
//Simple conversion function //converts selected number of decimal places to chars, //including sign if needed. //leading zeroes are not suppressed. // //buf - char buffer to write resulting string to //num - number to convert //places - number of decimal places to convert void _num_to_str(char *buf,int16_t num,uint8_t places); //Advanced conversion function //converts selected number of decimal places to chars, //including sign if needed. //Supports suppression of leading zeroes. // //buf - char buffer to write resulting string to //num - number to convert //places - number of decimal places to convert //Uncomment this to show unary '+' if value is positive //#define SGN_SHOW_POSITIVE 1 void _num_to_str_a(char *buf,int16_t num,uint8_t places);
Первая — совсем простая функция. Складывает указанное количество цифр числа в переданный буфер. Если цифр меньше указанного количества — добавляются нули. По необходимости добавляется минус (буфер должен быть достаточного размера, чтобы в этом случае его вместить).
Вторая более продвинута. Нули не добавляются, оставшееся перед числовой записью место заполняется пробелами. Место под знак резервируется всегда, так что по факту запись будет занимать на экране places+1 символ. Если раскомментировать дефайн SGN_SHOW_POSITIVE, знак перед числом (‘+’) будет добавлен, даже если число положительное — может быть удобно для разных вольтметров; иначе в этом случае добавляется пробел.
Одна из вышеописанных функций используется в LCD_PutInt(), и может быть заменена по вкусу — в исходнике есть обе. Дефайн CHARS_PER_INT перед LCD_PutInt() как раз и обозначает количество знакомест, отводимых под число (без учета знака; место под него резервируется неявно).
Скачать драйвер можно тут.