Подписка на новости

Опрос

Нужны ли комментарии к статьям? Комментировали бы вы?

Реклама

 

2001 №7

Применение знакосинтезирующих индикаторов фирмы Data Vision

Узенгер Алексей


При разработке микроконтроллерных устройств перед разработчиком ставится задача, какую микросхему использовать при проектировании. Выбор микроконтроллеров (МК) довольно широк, а возможности, как правило, примерно одинаковы. Автор использовал МК PIC16F873 фирмы Microchip, а также ЖКИ DV-16230 фирмы Data Vision. Описание этого микроконтроллера можно найти на www.microchip.com. При проектировании использовалась среда разработки MPLAB с ее базовым языком ассемблером. Нередко можно услышать, что этот язык устарел и что предпочтительнее использовать современный язык программирования — С. Но, как мы увидим далее, используя макросы и подпрограммы, ассемблер не так уж плох. Причем, можно создавать вполне читаемый текст, если сформировать для себя «правила» программирования и придерживаться их.

Рис 1. Схема подключения МК и ЖКИ

На рис. 1 представлена схема подключения МК и ЖКИ. На схеме видна разбросанность выводов на МК, которые соединяются с ЖКИ. Это связано только с тем, что микросхема на макетной плате отрабатывалась для другого устройства и временно была переориентирована на работу с ЖКИ. Для связи МК с контроллером ЖКИ используется семь выводов. Три из них (RS, R/W, E) — управляющие, они настроены на вывод. Остальные (DB4-DB7) служат для передачи данных — эти выводы в процессе работы программа настраивает и на ввод, и на вывод. Для работы используется 4-разрядная шина. Для более детального ознакомления с командами контроллера ЖКИ можно обратиться к литературе [2].

Обозначим параметры:

#define LCD_E PORTA, 5 ;Сигнал разрешения
#define LCD_RW PORTB, 0 ;Запись/Чтение
#define LCD_RS PORTC, 0 ;Выбор режима работы
#define LCD_DB0 PORTC, 1 ;Шина данных 4
#define LCD_DB1 PORTC, 3 ;Шина данных 5
#define LCD_DB2 PORTC, 4 ;Шина данных 6
#define LCD_DB3 PORTC, 5 ;Шина данных 7
;
LevelLCDLine1 EQU 0xA0; массив данных, отображенных в LCD индикаторе линия 1
LevelLCDLine2 EQU 0xB0; массив данных, отображенных в LCD индикаторе линия 2
LevelLCDLine3 EQU 0xC0
;
#define bLCDWrite theLCDVector, 0 ; (1) — запись данных (0) — команды
#define bLCD_BF theLCDVector, 1 ; флаг занятости LCD
#define bLCD_Work theLCDVector, 2 ; готовность LCD к работе
;
; — параметры входа в «Метод Записи Информации в Область Отображения»
#define bCreateLine theLCDVector1Create, 0
; (0) — линия вывода 1
; (1) — линия вывода 2
;
; — параметры «Сдвиг выведенной информации»
#define bLCDGoWindowActiv theLCDGoWindowVector, 0
; (1) — включено
#define bLCDGoWindowTwo theLCDGoWindowVector, 1
; (0) — информация выводится только в конкретную строчку
; (1) — информация с первой строчки переходит на вторую
#define bLCDGoWindowLine theLCDGoWindowVector, 2
; (0) — линия вывода 1
; (1) — линия вывода 2
#define bLCDGoWindowCircle theLCDGoWindowVector, 3
; (0) — смещение информации
; (1) — циклический вывод информации в заданной области
#define bLCDGoWindowGoing theLCDGoWindowVector, 4
; (0) — направление — ВПРАВО
; (1) — направление — ВЛЕВО

На рис. 2 показана структура памяти, выбранная автором. В контроллере ЖКИ расположена память ОЗУ, содержимое которой непосредственно отображается на поле ЖКИ. При желании из нее всегда можно считать и в нее можно записывать, создавая, таким образом, процедуры для работы с ЖКИ.

В настоящей статье использован следующий метод работы с памятью. В области памяти МК, в банке 1, отводится буфер, который содержит точную копию данных ОЗУ контроллера ЖКИ. Методы изменяют информацию в буфере, а по окончании выполнения преобразований, перезаписывают ОЗУ контроллера ЖКИ, когда он свободен. Может возникнуть вопрос: зачем так нерационально расходовать память. Расход памяти составляет 2ґ16 байт (размер поля ЖКИ). Автор исходил из того, что время выполнения методов (например, при смещении данных) значительно меньше, чем при работе непосредственно с памятью ОЗУ контроллера ЖКИ. Всю работу по преобразованию данных МК берет на себя, не затрагивая контроллер ЖКИ. За ним остается только задача вовремя выводить требуемую информацию.

Обозначим память в банке 0:

Cblock 0x20
; — переменные Метода Записи Информации в Область Отображения
theLCDUkazatelCreateH ; — указатель начала строки
theLCDUkazatelCreateL ; — указатель начала строки
theLCDVector1Create ; — параметры метода
; — внутренние переменные
theLCDDataCreateH ; high указателя предложения
theLCDDataCreateL ; low указателя предложения
theLCDDataAdresCreate ; указатель для косвенной записи информации в ОЗУ
theLCDDataCreatePosition ; отступ позиции от начала строчки
; — Сдвиг выведенной информации
theLCDGoWindowVector
theLCDGoWindowDataEnd
theLCDGoWindowAdrBegin
theLCDGoWindowAdrEnd
endc

Когда начинаешь считать последние оставшиеся байты в памяти программ, возникает мысль, что память используется неразумно и что код программы насыщен «водой». Возможный выход из такой ситуации — создание подпрограмм, которые уменьшают код, но загружают стек. Еще один способ — использование макросов, которые по своему образу и подобию создают код, незначительно отличающийся от исходного. Ниже приведены обозначения макросов.

1. Выбор банков. Этот макрос предназначен для простоты восприятия кода программы и часто оберегает от лишних ошибок.

bank0 macro
bcf STATUS, RP0
bcf STATUS, RP1
endm
bank1 macro
bsf STATUS, RP0
bcf STATUS, RP1
endm …

2. Вывод текста. Макрос предназначен для позиционного вывода информации в область памяти буфера. Ниже приведен макрос вывода слов в строку 1, по аналогии строится макрос вывода в строку 2.

Вывеcти_текст_в_строку_1 macro LabelH, LabelL, position
bcf bCreateLine
Вывести_текст position
endm

Вывести_текст macro position
movlw position
movwf theLCDDataCreatePosition
movlw LabelH
movwf theLCDUkazatelCreateH
movlw LabelL
movwf theLCDUkazatelCreateL
Call CreateWindowLCD
endm

3. Запись команды, константы, рабочего регистра в ЖКИ. Эти три макроса непосредственно посылают управляющие слова либо данные в контроллер ЖКИ.

Записать_команду_в_LCD macro command
movlw command
movwf theLCDdata
bcf bLCDWrite
call WriteLCD
endm
Записать_константу_в_LCD macro const
movlw const
movwf theLCDdata
bsf bLCDWrite
call WriteLCD
endm
Записать_W_в_LCD macro
movwf theLCDdata
bsf bLCDWrite
call WriteLCD
endm

Ниже обозначены подпрограммы.
1. Запись тетрады с предварительной проверкой загруженности контроллера ЖКИ. Процедура выводит младшие четыре бита на порты ввода-вывода, проверив предварительно, что контроллер ЖКИ готов к приему данных.

WriteLCDnibblov call ReadLCD_BF
bcf LCD_DB3
bcf LCD_DB2
bcf LCD_DB1
bcf LCD_DB0
btfsc theLCDdata, 0
bsf LCD_DB0
btfsc theLCDdata, 1
bsf LCD_DB1
btfsc theLCDdata, 2
bsf LCD_DB2
btfsc theLCDdata, 3
bsf LCD_DB3
bsf LCD_E
bcf LCD_E
Return

2. Запись данных/команд в ЖКИ. Данная процедура выводит байт в контроллер ЖКИ, предварительно разбив на тетрады.

WriteLCD btfsc bLCDWrite
bsf LCD_RS
swapf theLCDdata, F
call WriteLCDnibblov
swapf theLCDdata, F
call WriteLCDnibblov
bcf LCD_RS
Return

3. Формирование флага занятости контроллера ЖКИ. Процедура перенастраивает выводы DB4-DB7 на прием и производит опрос бита занятости контроллера ЖКИ. После прочтения бита занятости выводы DB4-DB7 восстанавливаются на вывод информации. Если контроллер ЖКИ готов к приему данных, то происходит выход из процедуры. В противном случае происходит повторный цикл опроса. Таким образом, если контроллер ЖКИ не работает, то будет иметь место бесконечный цикл.

ReadLCD_BF bcf bLCD_BF
clrf PORTC
bank1
movlw b'01111010' ; 1, 3, 4, 5 — изменяются
movwf TRISC
bank0
bcf LCD_RS
bsf LCD_RW
bsf LCD_E
bcf LCD_E
btfsc LCD_DB3
bsf bLCD_BF
bsf LCD_E
bcf LCD_E
bcf LCD_RW
clrf PORTC
bank1
movlw b'01000000'
movwf TRISC
bank0
btfsc bLCD_BF
goto ReadLCD_BF
btfsc bLCDWrite
bsf LCD_RS
Return

4. Очистка поля ЖКИ (ОЗУ МК). Процедура очищает память буфера, записывая в него код символа, который соответствует пустому полю в фонтах контроллера ЖКИ.

ResetLCD movlw LevelLCDLine1
movwf FSR
ResetLCDNext bank1
movlw __
movwf INDF
bank0
incf FSR, F
movf FSR, W
sublw LevelLCDLine3
btfss STATUS, Z
Goto ResetLCDNext
Return

5. Очистка поля ЖКИ (ОЗУ контроллера ЖКИ). Эта процедура загружает указатель контроллера ЖКИ в начало блока памяти первой строки и далее записывает в него код символа, который соответствует пустому полю в фонтах контроллера ЖКИ. Не стоит забывать о том, что контроллер ЖКИ настроен на инкрементацию указателя после записи байта данных. Для второй строки нужно создать аналогичный макрос, перезаписав команду на b'11000000'.

Рис. 2. Распределение памяти
RewriteLCDLine1 Записать_команду_в_LCD b'10000000'
clrf theLCDschet
RewriteLCDLine1Next Записать_константу_в_LCD __
incf theLCDschet, F
btfss theLCDschet, 4
goto RewriteLCDLine1Next
Return

6. Перерисовка поля ЖКИ (ОЗУ МК => ОЗУ контроллера LCD). Данная процедура очень похожа на RewriteLCDLine1, различие состоит лишь в том, что байт данных берется из соответствующей ячейки памяти буфера. Тем самым эти процедуры производят непосредственную передачу данных из буфера в память контроллера ЖКИ.

UpdateLCDLine1 Записать_команду_в_LCD b'10000000'
movlw LevelLCDLine1
movwf FSR
clrf theLCDschet
UpdateLCDLine1Next bank1
movf INDF, W
bank0
Записать_W_в_LCD
incf FSR, F
incf theLCDschet, F
btfss theLCDschet, 4
goto UpdateLCDLine1Next
Return

7. Инициализация ЖКИ (выполняется непосредственно после загрузки МК). Она настраивает системный интерфейс контроллера ЖКИ на работу с 4-разрядной шиной. Таким образом, с 1 по 4 шаг работает 8-разрядная шина, а начиная с 5-го — 4-разрядная.

InitLCD
; — передается старшая часть байта команды
bcf LCD_RS ; — говорит о записи команды
; — 1
movlw 0x03
movwf theLCDdata
call WriteLCDnibblov
; — 2
call WriteLCDnibblov
; — 3
call WriteLCDnibblov
; — 4
; — установка 4-битной передачи
movlw 0x02
movwf theLCDdata
call WriteLCDnibblov
; — далее команды передаются байтами
; — 5 — установка размерности интерфейса
Записать_команду_в_LCD b'00101000'
; — 6 — выключение LCD
Записать_команду_в_LCD b'00001000'
; — 7 — очистка экрана
Записать_команду_в_LCD b'00000001'
; — 8 — адресный регистр установлен в 0x00
Записать_команду_в_LCD b'00000010'
; — 9 — установка направления движения курсора
Записать_команду_в_LCD b'00000110'
; -10 — включение экрана
Записать_команду_в_LCD b'00001110'
bsf bLCD_Work

В памяти ПЗУ контроллера ЖКИ прошиты фонты — рис. 3. Также существует возможность записи своих символов в ОЗУ контроллере ЖКИ (CG RAM) и использование их в дальнейшем. Коды ASCII символов не совпадают с кодировкой фонтов, прошитых в контроллере ЖКИ. Создадим свою таблицу интерпретации символов.

; — русский алфавит
_А_ EQU 0x31
_а_ EQU 0x61
_Б_ EQU 0xA0
_б_ EQU 0xB2

; — латинский алфавит
_A_ EQU 0x41
_a_ EQU 0x61
_B_ EQU 0x42
_b_ EQU 0x62

; — окончание фразы
__end_ EQU 0x2000

Запишем в память программ МК фразы, которые необходимо выводить в процессе работы программы.

Hello_World data _H_, _e_, _l_, _l_, _o_, __, _W_, _o_, _r_, _l_, _d_, _воскл_+__end_
Проверка data _П_, _р_, _о_, _в_, _е_, _р_, _к_, _а_+__end_

Для того чтобы вывести на ЖКИ строчку «Проверка» с отступом в три символа, необходимо записать следующую команду.

Вывести_текст_в_строку_1 high Проверка, low Проверка, .3

Ниже приведена классификация методов работы с информацией.1. Метод записи информации из памяти программ МК в буфер отображения на поле ЖКИ является механизмом выборки текстовой информации из области памяти программ. На начало строки источника указывают theLCDUkazatelCreateH и theLCDUkazatelCreateL. На начало строки приемника указывает theLCDDataCreatePosition и бит указателя строки bCreateLine. Конец строки определяется кодом __end_ , который извлекается из памяти программ вместе с данными.

;---------------------------------------------------------------------------------
; вх. параметры:
; theLCDUkazatelCreateH ; — указатель начала строки high
; theLCDUkazatelCreateL ; — указатель начала строки low
; theLCDVector1Create ; — параметры метода
; используемые переменные:
; theLCDDataCreateH
; theLCDDataCreateL
; theLCDDataAdresCreate
; theLCDDataCreatePosition
;---------------------------------------------------------------------------------
CreateWindowLCD movf theLCDDataCreatePosition, W
btfss bCreateLine
goto $+3
addlw LevelLCDLine2
goto $+2
addlw LevelLCDLine1
movwf FSR

CreateWindowLCDEnd movf theLCDUkazatelCreateH, W
bank2
movwf EEADRH
bank0
movf theLCDUkazatelCreateL, W
bank2
movwf EEADR
bank3
bsf EECON1, EEPGD
bsf EECON1, RD
nop
nop
bcf STATUS, C
bank2
movf EEDATA, W
bank0
movwf theLCDDataCreateL
bank2
movf EEDATH, W
bank0
movwf theLCDDataCreateH
;
movf theLCDDataCreateL, W
bank1
movwf INDF
bank0
incfsz theLCDUkazatelCreateL, F
goto $+2
incf theLCDUkazatelCreateH, F
incf FSR, F
btfss theLCDDataCreateH, 5
goto CreateWindowLCDEnd
;
btfss bCreateLine
goto $+3
Call UpdateLCDLine2
goto $+2
Call UpdateLCDLine1
bcf bCreateLine
Return ; Все, сообщение выведено.

2. Метод сдвига выведенных данных. При вызове этого метода осуществляется проверка битов настройки, которые расписаны выше в параметрах. Этот метод удобно использовать в обработчике прерываний, включая его в тот момент, когда он необходим. Он реализует механизм сдвига информации либо влево, либо вправо, работает с одной-двумя строками, может сдвигать информацию за экран, либо замыкать циклически ее вывод на ЖКИ. Все эти параметры определяются битами настройки метода.

;---------------------------------------------------------------------------------
; вх. параметры
; theLCDGoWindowVector
; theLCDGoWindowDataEnd
; theLCDGoWindowAdrBegin
; theLCDGoWindowAdrEnd
;---------------------------------------------------------------------------------
GoWindow btfss bLCDGoWindowActiv
goto GoWindowLineEnd
btfss bLCDGoWindowTwo
goto GoWindowOne
goto GoWindowTwo
; — для перерисовки одной строки
GoWindowOne btfss bLCDGoWindowLine
goto GoWindowLine1
goto GoWindowLine2
GoWindowLine1
Call RewriteLCDLine1
movlw LevelLCDLine1
movwf theLCDGoWindowAdrBegin
movlw LevelLCDLine2
movwf theLCDGoWindowAdrEnd
goto GoWindowLineGoing
GoWindowLine2
Call RewriteLCDLine2
movlw LevelLCDLine2
movwf theLCDGoWindowAdrBegin
movlw LevelLCDLine3
movwf theLCDGoWindowAdrEnd
goto GoWindowLineGoing
; — для перерисовки двух строк
GoWindowTwo
Call RewriteLCDLine1
Call RewriteLCDLine2
movlw LevelLCDLine1
movwf theLCDGoWindowAdrBegin
movlw LevelLCDLine3
movwf theLCDGoWindowAdrEnd
goto GoWindowLineGoing
; — Какое направление перерисовки ?
GoWindowLineGoing
btfss bLCDGoWindowGoing
goto GoWindowLineRIGHT
goto GoWindowLineLEFT
GoWindowLineLEFT
; — Как выводить информацию? Циклически или нет?
btfsc bLCDGoWindowCircle
goto GoWindowLineCircleLEFT
movlw __
goto GoWindowLineLEFT_A
GoWindowLineCircleLEFT
movlw .1
subwf theLCDGoWindowAdrEnd, W
movwf FSR
bank1
movf INDF, W
bank0
goto GoWindowLineLEFT_A
; — тело модуля
GoWindowLineLEFT_A
movwf theLCDGoWindowDataEnd
movf theLCDGoWindowAdrEnd, W
movwf FSR
decf FSR, F
GoWindowLineLEFT_B
decf FSR, F
bank1
movf INDF, W
incf FSR, F
movwf INDF
bank0
decf FSR, F
movf FSR, W
subwf theLCDGoWindowAdrBegin, W
btfss STATUS, Z
goto GoWindowLineLEFT_B
movf theLCDGoWindowDataEnd, W
bank1
movwf INDF
bank0
goto GoWindowLineall
GoWindowLineRIGHT
; — Как выводить информацию? Циклически или нет?
btfsc bLCDGoWindowCircle
goto GoWindowLineCircleRIGHT
movlw __
goto GoWindowLineRIGHT_A
GoWindowLineCircleRIGHT
movf theLCDGoWindowAdrBegin, W
movwf FSR
bank1
movf INDF, W
bank0
goto GoWindowLineRIGHT_A
; — тело модуля
GoWindowLineRIGHT_A
movwf theLCDGoWindowDataEnd
movf theLCDGoWindowAdrBegin, W
movwf FSR
GoWindowLineRIGHT_B
incf FSR, F
bank1
movf INDF, W
decf FSR, F
movwf INDF
bank0
incf FSR, F
movf FSR, W
addlw .1
subwf theLCDGoWindowAdrEnd, W
btfss STATUS, Z
goto GoWindowLineRIGHT_B
movf theLCDGoWindowDataEnd, W
bank1
movwf INDF
bank0
goto GoWindowLineall
; — перенести информацию на LCD-индикатор
GoWindowLineall
btfss bLCDGoWindowTwo
goto $+4
call UpdateLCDLine1
call UpdateLCDLine2
goto GoWindowLineEnd
btfsc bLCDGoWindowLine
goto $+3
call UpdateLCDLine1
goto $+2
call UpdateLCDLine2
goto GoWindowLineEnd
GoWindowLineEnd
Return
Рис 3. Русско-английские фонты

Как использовать данный метод. Пусть нам необходимо вывести строчку «Hello World!» с отступом в один символ и через 1 с смещать ее слева направо через весь экран в цикле. Необходимо выполнить следующую последовательность действий:
1. После инициализации ЖКИ (процедура InitLCD) вывести строку:

Call InitLCD
Вывести_текст_в_строку_1 high Hello_World, low Hello_World, .1

2. Настроить модуль метода сдвига. Биты конфигурации расписаны в параметрах.

movlw b'00011011'
movwf theLCDGoWindowVector

3. Организовать прерывания от любого таймера через 1. с и вызвать метод GoWindow.

Call GoWindow
Рис. 4

Таким образом, мы будем наблюдать перемещение фразы, как это показано на рис. 4.В данной статье затронут всего один способ вывода информации на ЖКИ. Можно придумать большое количество разнообразных вариантов. Чем оригинальнее производится вывод информации, тем приятнее работать с прибором. Ведь недаром западные разработчики уделяют столь большое внимание оформлению приборов, расходуя драгоценное время на «мелочи». Но именно на этих «мелочах», по мнению автора, и формируется отношение и к прибору, и, следовательно, к его разработчикам.

Литература

  • PIC16F87X. Data Sheet., Microchip Technology Inc., 1999.
  • Библиотека Электронных Компонентов. Жидкокристаллические индикаторы фирмы Data International. — М.: ДОДЭКА, 1999. — 64 c.
  • Электронные Компоненты. Каталог. — М.: Платан, 2000. С. 120.

Другие статьи по данной теме:

Сообщить об ошибке