Программная реализация обмена данными со знакосинтезирующим ЖКИ (PIC16F628A). Часть 2. Четырехбитный интерфейс

В данной статье приведены примеры программной реализации обмена данными микроконтроллера PIC16F628A с HD44780, KS0066 -совместимым знакосинтезирующим ЖКИ (для схемы из статьи "Подключение знакосинтезирующего ЖКИ к контроллеру (PIC16F628A)".

Приведенные примеры предполагают использование ЖКИ 16х2 и четырехбитного интерфейса. Кроме этого, в статье приводятся примеры программирования собственного символа в CGRAM и вывода его на ЖКИ (пример работы с пользовательским набором символов).

Поскольку в данных примерах мы будем пользоваться четырехбитным интерфейсом, то линии DB0…DB3 (RA6, RA2, RB7, RB3) — не используются (смело можете их отпаять и занять освободившиеся ножки контроллера чем-нибудь другим).

Как прошить в CGRAM пользовательский символ? Да очень просто. Разберемся — как устроена CGRAM:

Таблица для программирования CGRAM ЖКИ

Каждый символ 5х8 занимает в памяти CGRAM восемь байт (по одному байту на строку). Младшие 5 бит каждого байта определяют какие из пяти точек строки должны гореть, а какие нет. Старшие три бита — не используются.

CGRAM имеет размер 64 байта, поэтому для ее адресации используются шесть младших бит адреса (26=64). Три младших бита (из используемых) адресуют номер строки для текущего символа, а три старших бита (из используемых) адресуют номер символа знакогенератора. Взгляните на рисунок слева и вам все станет ясно.

Внимание! В родной документации на KS0066U допущены ошибки: 1) почему-то биты, указывающие номер символа всегда равны нулю; 2) не верно описана команда function set в примерах инициализации. В доке на HD44780 все нормально.

Как узнать, что контроллер ЖКИ освободился? Нужно просто выставить на линии RS низкий уровень (RS=0), на линии R/W высокий (R/W=1), тогда при включении передачи (E=1) контроллер ЖКИ выставит на линии DB7 свое состояние (если используется четырехбитный интерфейс, то только в старшем принятом полубайте). Если DB7=1, то ЖКИ занят (BUSY), если DB7=0, то ЖКИ свободен и готов к приему следующей посылки.

Следует учитывать, что проверка начинает работать не сразу, а после нескольких команд инициализации (у всех по разному), поэтому во время инициализации лучше не проверять состояние контроллера ЖКИ, а просто ждать положенное на выполнение команды время.

Подключение линий ЖКИ к портам контроллера:

E-RA0, RS-RA1, R/W-RA7, DB7-RB4, DB6-RB5, DB5-RB2, DB4-RB6

Передача данных по четырехбитному интерфейсу работает следующим образом: сначала передается старший полубайт сообщения, а затем младший (чтение аналогично). Например, если вы хотите записать в DDRAM байт 0011 0101, то это будет выглядеть так:

 movlw  .3        ; .3=0011 - старший полубайт
 movwf  M_byte    ; записываем это значение в переменную для передачи
 call   in_port   ; процедура, которая устанавливает уровни на выходах МК,
                  ; подключенных к линиям DB7..DB4 в соответствии
                  ; со значениями, записанными в M_byte
 bsf    PortA, 1  ; RS=1
 bcf    PortA, 7  ; R/W=0
 call   zapis     ; процедура, которая на 2 мкс выставляет "1" на линии E
 movlw  .5        ; .5=0101 - младший полубайт
 movwf  M_byte    ; записываем это значение в переменную для передачи
 call   in_port   ; процедура, которая устанавливает уровни на выходах МК,
                  ; подключенных к линиям DB7..DB4 в соответствии
                  ; со значениями, записанными в M_byte
 call   zapis     ; еще раз устанавливать уровни на линиях RS и R/W
                  ; нет необходимости, они не изменились (RS=0, R/W=0)

Единственное исключение — первая команда инициализации (FUNCTION SET). Для четырехбитного интерфейса при передаче первой команды инициализации надо сначала два раза передать старший полубайт, а потом младший полубайт. Например для инициализации четырехбитного интерфейса, двухстрочного ЖКИ, размер символа 5х8 (00101000):

 movlw .2       ; DB7...DB4= 0010 - старший полубайт
 movwf M_byte   ; записать это значение в переменную для передачи
 call  in_port  ; процедура, которая устанавливает уровни на выходах МК,
                ; подключенных к линиям DB7..DB4 в соответствии
                ; со значениями, записанными в M_byte
 bcf   PortA, 1 ; RS=0 
 bcf   PortA, 7 ; RW=0 
 call  zapis    ; передача в ЖКИ
 call  zapis    ; передаем старший полубайт второй раз
 movlw .8       ; DB7...DB4=1000 - младший полубайт
 movwf M_byte   ; записать это значение в переменную для передачи
 call  in_port  ; процедура, которая устанавливает уровни на выходах МК,
                ; подключенных к линиям DB7..DB4 в соответствии
                ; со значениями, записанными в M_byte
 call  zapis    ; выставляем E=1 на 2мкс (передача в ЖКИ)

Пример программирования символа в CGRAM (загрузим в CGRAM символ, как на рисунке выше):

;*** 01 010 000 - set CGRAM - установ.адрес CGRAM на 1-ю строку символа №2
;*** адрес устанавливается один раз, после записи/чтения по этому адресу
;*** указатель (как и в случае с DDRAM) автом-чески сдвинется вправо/влево,
;*** в зависимости от того, что указано при инициализации
 movlw .5      ; DB7...DB4=0101 - старший полубайт
 movwf M_byte  ; записать это значение в переменную для передачи
 call  in_port ; процедура, которая устанавливает уровни на выходах МК,
               ; подключенных к линиям DB7...DB4
 bcf   PortA,1 ; RS=0
 bcf   PortA,7 ; R/W=0
 call  zapis   ; на 2 мкс выставляем "1" на линии E (запись в ЖКИ)
 movlw .0      ; DB7...DB4=0000 - младший полубайт
 movwf M_byte  ; записать это значение в переменную для передачи
 call  in_port ; процедура, которая устанавливает уровни на выходах МК
               ; подключенных к линиям DB7...DB4
 call  zapis   ; на 2 мкс выставляем "1" на линии E (запись в ЖКИ)
;*** Пауза >39 мкс **********************
 call  pause1
;*** Запись восьми байт, определяющих символ, в CGRAM
;*** 1) 0001 1111 2) 0000 0100 3) 0001 1111 4) 0000 0000
;*** 5) 0001 1101 6) 0001 0010 7) 0001 1111 8) 0000 0000
;*** Пишем первый байт ******************
 bsf   PortA,1 ; RS=1, R/W уже установлен в ноль
 movlw .1      ; DB7...DB4=0001 - старший полубайт
 movwf M_byte  ; записать это значение в переменную для передачи
 call  in_port ; процедура, которая устанавливает уровни на выходах МК,
               ; подключенных к линиям DB7...DB4
 call  zapis   ; на 2 мкс выставляем "1" на линии E (запись в ЖКИ)
 movlw .15     ; DB7...DB4=1111 - младший полубайт
 movwf M_byte  ; записать это значение в переменную для передачи
 call  in_port ; процедура, которая устанавливает уровни на выходах МК,
               ; подключенных к линиям DB7...DB4
 call  zapis   ; на 2 мкс выставляем "1" на линии E (запись в ЖКИ)
;*** Пауза >43 мкс **********************
 call  pause1
;*** Пишем второй байт ******************
 movlw .0      ; DB7...DB4=0000 - старший полубайт
 movwf M_byte  ; записать это значение в переменную для передачи
 call  in_port ; процедура, которая устанавливает уровни на выходах МК,
               ; подключенных к линиям DB7...DB4
 call  zapis   ; на 2 мкс выставляем "1" на линии E (запись в ЖКИ)
 movlw .4      ; DB7...DB4=0100 - младший полубайт
 movwf M_byte  ; записать это значение в переменную для передачи
 call  in_port ; процедура, которая устанавливает уровни на выходах МК,
               ; подключенных к линиям DB7...DB4
 call  zapis   ; на 2 мкс выставляем "1" на линии E (запись в ЖКИ)
;*** Пауза >43 мкс **********************
 call  pause1
;*** Пишем третий байт ******************
 movlw .1      ; DB7...DB4=0001 - старший полубайт
 movwf M_byte  ; записать это значение в переменную для передачи
 call  in_port ; процедура, которая устанавливает уровни на выходах МК,
               ; подключенных к линиям DB7...DB4
 call  zapis   ; на 2 мкс выставляем "1" на линии E (запись в ЖКИ)
 movlw .15     ; DB7...DB4=1111 - младший полубайт
 movwf M_byte  ; записать это значение в переменную для передачи
 call  in_port ; процедура, которая устанавливает уровни на выходах МК,
               ; подключенных к линиям DB7...DB4
 call  zapis   ; на 2 мкс выставляем "1" на линии E (запись в ЖКИ)
;*** Пауза >43 мкс **********************
 call  pause1
;*** Пишем четвертый байт ***************
 movlw .0      ; DB7...DB4=0000 - старший полубайт
 movwf M_byte  ; записать это значение в переменную для передачи
 call  in_port ; процедура, которая устанавливает уровни на выходах МК,
               ; подключенных к линиям DB7...DB4
 call  zapis   ; на 2 мкс выставляем "1" на линии E (запись в ЖКИ)
 movlw .0      ; DB7...DB4=0000 - младший полубайт
 movwf M_byte  ; записать это значение в переменную для передачи
 call  in_port ; процедура, которая устанавливает уровни на выходах МК,
               ; подключенных к линиям DB7...DB4
 call  zapis   ; на 2 мкс выставляем "1" на линии E (запись в ЖКИ)
;*** Пауза >43 мкс **********************
  call pause1
;*** Пишем пятый байт *******************
 movlw .1      ; DB7...DB4=0001 - старший полубайт
 movwf M_byte  ; записать это значение в переменную для передачи
 call  in_port ; процедура, которая устанавливает уровни на выходах МК,
               ; подключенных к линиям DB7...DB4
 call  zapis   ; на 2 мкс выставляем "1" на линии E (запись в ЖКИ)
 movlw .13     ; DB7...DB4=1101 - младший полубайт
 movwf M_byte  ; записать это значение в переменную для передачи
 call  in_port ; процедура, которая устанавливает уровни на выходах МК,
               ; подключенных к линиям DB7...DB4
 call  zapis   ; на 2 мкс выставляем "1" на линии E (запись в ЖКИ)
;*** Пауза >43 мкс **********************
 call  pause1
;*** Пишем шестой байт ******************
 movlw .1      ; DB7...DB4=0001 - старший полубайт
 movwf M_byte  ; записать это значение в переменную для передачи
 call  in_port ; процедура, которая устанавливает уровни на выходах МК,
               ; подключенных к линиям DB7...DB4
 call  zapis   ; на 2 мкс выставляем "1" на линии E (запись в ЖКИ)
 movlw .2      ; DB7...DB4=0010 - младший полубайт
 movwf M_byte  ; записать это значение в переменную для передачи
 call  in_port ; процедура, которая устанавливает уровни на выходах МК,
               ; подключенных к линиям DB7...DB4
 call  zapis   ; на 2 мкс выставляем "1" на линии E (запись в ЖКИ)
;*** Пауза >43 мкс **********************
 call  pause1
;*** Пишем седьмой байт *****************
 movlw .1      ; DB7...DB4=0001 - старший полубайт
 movwf M_byte  ; записать это значение в переменную для передачи
 call  in_port ; процедура, которая устанавливает уровни на выходах МК,
               ; подключенных к линиям DB7...DB4
 call  zapis   ; на 2 мкс выставляем "1" на линии E (запись в ЖКИ)
 movlw .15     ; DB7...DB4=1111 - младший полубайт
 movwf M_byte  ; записать это значение в переменную для передачи
 call  in_port ; процедура, которая устанавливает уровни на выходах МК,
               ; подключенных к линиям DB7...DB4
 call  zapis   ; на 2 мкс выставляем "1" на линии E (запись в ЖКИ)
;*** Пауза >43 мкс **********************
 call  pause1
;*** Пишем восьмой байт *****************
 movlw .0      ; DB7...DB4=0000 - старший полубайт
 movwf M_byte  ; записать это значение в переменную для передачи
 call  in_port ; процедура, которая устанавливает уровни на выходах МК,
               ; подключенных к линиям DB7...DB4
 call  zapis   ; на 2 мкс выставляем "1" на линии E (запись в ЖКИ)
 movlw .0      ; DB7...DB4=0000 - младший полубайт
 movwf M_byte  ; записать это значение в переменную для передачи
 call  in_port ; процедура, которая устанавливает уровни на выходах МК,
               ; подключенных к линиям DB7...DB4
 call  zapis   ; на 2 мкс выставляем "1" на линии E (запись в ЖКИ)
;*** Пауза >43 мкс **********************
 call  pause1

Всё, теперь этот запрограммированный в CGRAM символ можно вывести на ЖКИ, записав в DDRAM символ под номером 2. Вот пример вывода такого самостоятельно запрограммированного символа на четвертую позицию первой строки ЖКИ:

;*** Set DDRAM ADDRESS 1000 0011 (4-я позиция первой строки ЖКИ)
 bcf   PortA, 1  ; RS=0
 bcf   PortA, 7  ; R/W=0
 movlw .8        ; 1000 - старший полубайт
 movwf M_byte
 call  in_port
 call  zapis
 movlw .3        ; 0011 - младший полубайт
 movwf M_byte
 call  in_port
 call  zapis  
;*** Пауза >39 мкс ***
 call  pause1
;*** Вывод символа (для записи в RAM надо установить RS=1, R/W=0)
;*** Пишем символ под номером 2 (0000 0010)
 bsf   PortA,1   ; RS=1, R/W уже сброшен в 0, его не трогаем
 movlw .0        ; 0000
 movwf M_byte
 call  in_port
 call  zapis
 movlw .2        ; 0010
 movwf M_byte
 call  in_port
 call  zapis
;*** Пауза >43 мкс ***
 call  pause1

Как выглядят процедуры zapis, in_port, pause1 можно посмотреть в статье про реализацию связи по восьмибитному интерфейсу. Надеюсь, что теперь, вы без труда сможете переделать их под четырехбитный интерфейс.

Добавить комментарий