Шаг 4.5. Пишем длинные строчки в LCD.
Кажется, что в нашей программке все отлично - команды пишутся, строчки тоже... Но вот беда - если мы попробуем отослать строку длиннее, то она обрежется на восьмом символе.
Рисунок 1. Проблемы с отображением длинных строк.
Обращаемся к документации: "индикатор содержит ОЗУ размером 80 байт по адресам 0h - 27h и 40h - 67h для хранения данных (DDRAM), выводимых на индикатор. Адреса отображаемых на индикаторе символов распределены следующим образом:
Знакоместо | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|
Адрес | 0h | 1h | 2h | 3h | 4h | 5h | 6h | 7h | 40h | 41h |
Таким образом, первые восемь символов записываются подряд, начиная с адреса "0h", а вот для записи оставшихся двух необходимо ручками устанавливать нужный адрес для записи. Справедливости и злорадства ради заметим, что встроенная библиотека точно так же теряет девятый и десятый символы.
Что ж, проблема есть - так будем её решать!
Функция для отправки как отдельных, так и для последовательностей команд у нас уже есть, самое время изучить, а какие основные команды для МТ-10S1 вообще есть.
Таблица 1. Некоторые команды для дисплея MT-10S1.
Команда | DB7 | DB6 | DB5 | DB4 | DB3 | DB2 | DB1 | DB0 | Описание |
---|---|---|---|---|---|---|---|---|---|
Clear Display | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | Очищает индикатор и перемещает курсор в самую левую позицию |
Return Home | 0 | 0 | 0 | 0 | 0 | 0 | 1 | x | Перемещает курсор в левую позицию |
Entry Mode Set | 0 | 0 | 0 | 0 | 0 | 1 | ID | SH | Установка направления сдвига курсора (ID = 0/1 - влево/вправо) и разрешение сдвига дисплея (SH = 1) при записи в DDRAM |
Display ON/OFF control | 0 | 0 | 0 | 0 | 1 | D | C | B | Включает индикатор (D = 1) и выбирает тип курсора (C, B) |
Cursor or Display Shift | 0 | 0 | 0 | 1 | SC | RL | x | x | Выполняет сдвиг дисплея или курсора (SC = 0/1 - курсор/дисплей, RL = 0/1 - влево/вправо) |
Set DDRAM Address | 1 | ADD | Установка адреса для последующих операций и выбор области DDRAM |
Для того, чтобы писать длинные строки, нам потребуется единственная команда - Set DDRAM Address. Так, чтобы установить курсор для самую левую позицию, нужно будет послать команду 0b10000000, где крайняя левая единица относится к идентификатору самой команды, а "0000000" - адрес области DDRAM. Чтобы установить курсор в конец строки для записи 9 и 10 символов, используем команду 0b11000000, где адрес - "1000000", то есть 40h.
В принципе, этого уже достаточно для работы, однако нужно заметить, что дисплей не стирает написанное при переходе в начало строки, поэтому если сначала мы пошлём длинную строку, а затем короткую, то у нас получится "наложение" строк друг на друга - не очень-то красиво!
Рисунок 2. Проблема наложения строк на дисплее.
Поэтому перед тем, как писать строку, используем команду Clear Display - 0b00000001.
Смотрим, что у нас получается (рассмотрим только функцию передачи строки и main, остальное без изменений).
На Си:
const int DL_STAY_TEXT_ON_DISPLAY_MS = 2000; //задержка после передачи текста дисплею для возможности прочитать его, в мс ... //функция отправки дисплею строки, заканчивающейся нулём ('\0') void LCD_SendStr(byte* Str) { //команды дисплею const byte LCD_CMD_SET_BEGIN_OF_STR[] = {0b10000000, 0}; //переход в начало строки дисплея const byte LCD_CMD_SET_END_OF_STR[] = {0b11000000, 0}; //переход в конец строки дисплея (9 и 10 символы) const byte LCD_CMD_CLEAR_DISPLAY[] = {0x01, 0}; //очистка дисплея и переход в начало строки const byte LCD_MAX_SYMBOL_COUNT = 10; //максимальное количество символов - для того, чтобы не писать лишнего в память дисплея byte i; LCD_SendCommands(LCD_CMD_CLEAR_DISPLAY); i = 0; while ((Str[i] != 0) && (i < LCD_MAX_SYMBOL_COUNT)) { if (i == 8) //если пора "переходить" в конец строки (нужно записать 9 и 10 символы) - то изменяем адрес записи в дисплее LCD_SendCommands(LCD_CMD_SET_END_OF_STR); LCD_SendByte(Str[i], 1); i++; } } void main() { const byte LCD_CMD_INIT[] = {0b00110011, //команды для инициализации модуля 0b00110010, 0b00101000, 0b00001111, 0b00000001, 0b00000110, 0}; //строка на вывод char sText[] = "Hello,wrld"; char sMeow[] = "Meow"; //инициализация портов ввода-вывода DDRA = 0; PORTA = 0; DDRB = 0; PORTB = 0; DDRD = 0; PORTD = 0; //инициализация выводов для дисплея - на выход и на 0 ddrLCD |= (1 << LCD_A0_OUT_NUMBER) | (1 << LCD_E_OUT_NUMBER) | LCD_DATA_MASK; Delay_ms(DL_LCD_SWITCH_ON_MS); //задержка для дисплея после включения LCD_SendCommands(LCD_CMD_INIT); //инициализация дисплея набором константных команд LCD_SendStr(sText); //отправка текста Delay_ms(DL_STAY_TEXT_ON_DISPLAY_MS); //задержка для прочтения текста LCD_SendStr(sMeow); while(1) { Delay_ms(1); } }
На Паскале:
const DL_STAY_TEXT_ON_DISPLAY_MS = 2000; //задержка после передачи текста дисплею для возможности прочитать его, в мс ... //функция отправки дисплею строки, заканчивающейся нулём ('\0') procedure LCD_SendStr(var Str: String); const LCD_CMD_SET_BEGIN_OF_STR : array[2] of Byte = (%10000000, 0); //переход в начало строки дисплея LCD_CMD_SET_END_OF_STR : array[2] of Byte = (%11000000, 0); //переход в конец строки дисплея (9 и 10 символы) LCD_CMD_CLEAR_DISPLAY : array[2] of Byte = (0x01, 0); //очистка дисплея и переход в начало строки LCD_MAX_SYMBOL_COUNT = 10; //максимальное количество символов - для того, чтобы не писать лишнего в память дисплея var i: Integer; begin LCD_SendCommands(@LCD_CMD_CLEAR_DISPLAY[0]); i := 0; while ((Str[i] <> 0) and (i < LCD_MAX_SYMBOL_COUNT)) do begin if (i = 8) then //если пора "переходить" в конец строки (нужно записать 9 и 10 символы) - то изменяем адрес записи в дисплее LCD_SendCommands(@LCD_CMD_SET_END_OF_STR[0]); LCD_SendByte(Str[i], 1); inc(i); end; end; const Init: array[0.. 6] of Byte = (%00110011, //команды для инициализации модуля %00110010, %00101000, %00001111, %00000001, %00000110, 0); var sText, sMeow: string[10]; begin sText := 'Hello,wrld'; sMeow := 'Meow'; //инициализация портов ввода-вывода DDRA := 0; PORTA := 0; DDRB := 0; PORTB := 0; DDRD := 0; PORTD := 0; //инициализация выводов для дисплея - на выход и на 0 ddrLCD := ddrLCD or (1 shl LCD_A0_OUT_NUMBER) or (1 shl LCD_E_OUT_NUMBER) or LCD_DATA_MASK; Delay_ms(DL_LCD_SWITCH_ON_MS); //задержка для дисплея после включения LCD_SendCommands(@Init[0]); //инициализация дисплея LCD_SendStr(sText); //отправка текста Delay_ms(DL_STAY_TEXT_ON_DISPLAY_MS); //задержка для прочтения текста LCD_SendStr(sMeow); while(1) do Delay_ms(1); end.
Прошивка улучшенной версии программы тут.
В результате получаем следующее:
Автор - Moriam
Обсудить на форуме