Вы находитесь на странице: 1из 13

2-1/11.

"Разборки" с инициализацией графического модуля, осуществляемой по


1-му ("штатному") варианту, с задействованием флагов статуса. Режим чтения
байтов данных из оперативной памяти графического модуля. Пример
копирования элемента картинки "из пункта А в пункт Б" (через оперативную
память ПИКа).

Не трудно догадаться, что после "вождения носом по батарее", которое имело место
быть в предыдущем подразделе, неизбежно начнется поиск более оптимального
варианта инициализации графического модуля.
Диалектика "в чистом виде" ("жить - хорошо, но хорошо жить - еще лучше").
Вопрос: "Чем не мило то, что сваялось ранее, ведь железяка нормально работает"?
Ответ: транзистором. Он смотрится как некое "инородное тело", от которого имеется
маниакальное желание избавиться.
Проще говоря, а на фиг он нужен, ведь все гениальное просто?
Возразить на это просто нечем.
И именно потому, что люди постоянно ищут и находят ответы на подобного рода
вопросы, мы сейчас не шимпанзе, а человеки.
Так что, прошу осознать серьезность эволюционного момента и проникнуться… (тьфу
ты, запутался. Домыслите сами).
Вопрос: "Из чего выбирать"?
Ответ: из оставшихся вариантов инициализации.
2-й вариант инициализации отпадает, так как это та же "аналоговая гнусность", но
только "с другого бока".
Остается 1-й вариант инициализации графического модуля, который предлагают
разработчики ("штатный").
В "железе", это выглядит так:

1
После банального сравнения того, что было с тем, что есть, становится понятно, что
данный вариант, в "аппаратном смысле", более выигрышен.
И в самом деле, количество задействованных выводов портов - одно и то же, но
транзистор "моль съела".
Нет его. "Усоп" за ненужностью.
Мало того, и в "программном смысле" этот вариант более выигрышен.
Вопрос: "Почему"?
Ответ: потому, что в ходе инициализации графического модуля, не нужно программно
исполнять аж 2 инструкции: Display OFF (выключение дисплея) и Display StartLine
(выбор строки).
Вопрос: "Почему их не нужно программно исполнять"?
Ответ: потому, что они исполняются аппаратно (автоматически).
Вопрос: "Но для "запуска в работу" (инициализации) любого аппаратного процесса (а
тем более, нескольких) нужен строб? Где этот оболтус?".
Ответ: поосторожнее на поворотах. Соображение нужно иметь. Это вовсе и не
"оболтус", а вполне профессиональный "управленец", причем, в "ранге суперважняка".
Такого "на кривой козе не объедешь", а если и "объедешь", то "умоешься горькими
слезами".
Так что, хочешь - не хочешь, а "Боже царя храни" спеть придется.
Вопрос: "Неужели царь"?
Ответ: так точно. Самый натуральный. Если разрешит, то будет "счастье", а если не
разрешит, то будут "белые тапки" (и это еще мягко сказано).
Вопрос: "Пардон. А в чем заключаются его выдающиеся способности"?
Ответ: в том, что с этого строба начинается все сущее. Если, при данном "раскладе",
его не будет, то вместо него будет "легендарный Гитлер капут", причем, в особо
тяжелой форме.
Вопрос: "А если он (строб) будет, то какого счастья ждать"?
Ответ: всеобъемлющего. Но при условии, что в дальнейшем будут соблюдены
"правила игры".
А теперь конкретно.
Стробом является перепад от 1 к 0 на выводе внешнего сброса графического модуля
с названием RES.
Естественно, что для того чтобы такой перепад имел место быть, сначала нужно
озаботиться программным "выставлением", на выводе RES, единичного уровня, затем
подождать, как минимум, 1 мкс. (но лучше побольше), а только после этого программно
менять уровень 1 на уровень 0.
Сразу же после смены 1 на 0, происходит общий, аппаратный сброс всей "начинки"
графического модуля, после чего, так же аппаратно (автоматически), "запускаются в
работу" две упомянутые выше инструкции (Display OFF и Display StartLine).
Так как строб формируется в то время, когда Uпит. графического модуля установилось
и надежно зафиксировалось на уровне 5 вольт, то все "бяки", которые имели место
быть до этого общего, аппаратного сброса (см. предыдущий подраздел) - "по
барабану".
Если так можно выразиться, то после общего, аппаратного сброса, работа
графического модуля начинается "с чистого листа".
И никакого дополнительного транзистора не нужно.
И программно выполнять инструкцию Display OFF тоже не нужно.
С инструкцией Display OFF все ясно - выключение дисплея, а вот с инструкцией
Display StartLine - не очень.
Но это дело поправимое: в случае применения 1-го варианта инициализации
графического модуля, по умолчанию, автоматически, выставляется адрес 1-й строки
(00h).
То есть, если в дальнейшем, заполнение дисплея будет происходить с 1-й строки (как
в рассматриваемом случае), то инструкцию Display StartLine программно исполнять не
нужно.
Ее нужно программно исполнять только в том случае, когда, после инициализации
графического модуля, заполнение дисплея будет начинаться не с 1-й строки, а с
какой-нибудь другой.

2
Для обеспечения гарантированного исполнения "вышележащего", длительность
стробирующего импульса должна быть не менее 1 мкс.
Ну ладно, стробирующий импульс "сваяли", а дальше-то что?
Цитата из технического описания: "После деактивации сигнала RES (переключения
в логическую «1» с временем фронта не более 200нс) необходимо дождаться
сброса битов BUSY и RESET в регистре состояния обоих кристаллов или
выдержать паузу не менее 10 мкс. После этого модуль нормально
функционирует".
Так как, в данном случае, "упор" делается на флаги статуса, то на фиксированную
задержку "закрываю глаза".
Сразу же возникает вопрос: "А куда подевался флаг ON/OFF? Почему он
разработчиками замалчивается"?
"Это жу-жу неспроста"…
Так точно. Неспроста.
Пробовал "подпрячь".
Получился конфуз: рабочая точка программы "намертво зависает" в процедуре анализа
состояний флага ON/OFF.
Таким образом, получается, что в случае применения 1-го варианта инициализации,
этот флаг не сбрасывается.
Ну хоть бы намекнули (по-русски)!
Ладно. "Проехали". Хотя, к разработчикам и к сопровождающей их "обслуге", имеются
кое-какие, мелкие претензии.
Но еще большие претензии появляются после прочтения предложения "После этого
модуль нормально функционирует".
Детский вопрос: "С какой стати он будет нормально функционировать, если дисплей
выключен"?
Об этом - ни слова.
По всей видимости, это изречение предназначено для людей достаточно неординарных
(типа "догадайтесь сами").
В этом отношении, мы сильно отстали от американцев.
"Американский" пример (на вскидку):
1. Воткнуть вилку в розетку.
Внимание!!! Вилка это то, из чего торчат две круглые железяки типоразмера …
(рисунок прилагается), а в розетке (рисунки розеток различных фирм прилагаются),
есть две круглые дырки, в которые и нужно воткнуть эти круглые железяки.
Внимание!!! К вилке подключен электрический шнур (рисунок прилагается). Необходимо
проконтролировать, чтобы второй конец этого шнура находился в том изделии нашей
фирмы (рисунок прилагается), которое Вы пытаетесь включить.
В случае наличия квадратных, прямоугольных, N-угольных и прочих дырок, с формой,
отличной от круглой, просьба обращаться в наш многофункциональный, сервисный
центр быстрого реагирования (телефон …, E-mail …).
Наши высокопрофессиональные специалисты широкого, аварийного профиля,
оперативно Вам помогут в Вашей беде.
Внимание!!! Строго запрещается втыкать, в эти круглые дырки, человеческие
конечности, а также и прочие предметы, отличные от вилки (см. рисунок вилки)!
В случае наличия оного, возмущения и претензии не принимаются.
2. Указательным пальцем правой руки, нужно нажать на кнопку "Включение".
Внимание!!! Головой, ногой, а далее - по списку (список прилагается), нажимать на
кнопку "Включение" запрещается. В противном случае, к претензии, нужно будет
приложить справку об образовании, справку из психдиспансера и заключение терапевта
об отсутствии у Вас бешенства, эпилепсии, родильной горячки (далее - по списку.
Список прилагается).
Ну и так далее (N-страниц).

Пример для людей с чувством юмора, которые способны увидеть, в этом "идиотизме",
нечто большее, чем смех.
На первый взгляд, вроде как и смешно, но ведь и понятно, что именно и как именно
нужно делать, а чего делать нельзя!!! (скрытая форма обучения тому, чего человек не
знает).
3
Это гораздо лучше, чем описание типа: "После этого модуль нормально
функционирует".
"Муть в чистом виде".
Мне, как организму, не терпящему "мути", очень захотелось с ней как следует
разобраться (как быку с красной тряпкой).
Примечание: графический модуль стоит такую денюжку, что и разработчикам, и спецам
компании МЭЛТ, вполне можно было бы и подсуетиться.
Вот так и "родилась" следующая процедура "штатной" инициализации графического
модуля, с использованием его битов статуса (ниоткуда не скопирована. Made in
Здравый Смысл):
.................................
.................................
;********************************************************************************
; НАЧАЛО ПРОГРАММЫ.
;********************************************************************************
; Подготовительные операции.
;================================================================================
START bsf Status,RP0 ; Переход в 1-й банк.
clrf TrisB ; Все выводы портов В и С
clrf TrisC ; работают на выход.
bcf Status,RP0 ; Переход в 0-й банк.

bsf PortB,4 ; Подготовка к сбросу графического модуля.

bcf PortB,A0 ; Подготовка к исполнению команд.


bsf PortB,E1 ; Включение обеих
bsf PortB,E2 ; кристаллов.
;================================================================================
; Инициализация графического модуля.
;================================================================================
; Сброс графического модуля.
;-----------------------------------------
bcf PortB,4 ; Формирование импульса длительностью более
nop ; 1 мкс. По спаду импульса, выполняются
bsf PortB,4 ; инструкции "Display OFF" и "Display
; StartLine" (назначается адрес 1-й строки).
movlw b'00111111' ; Инструкция "Display ON"
movwf PortC ; (включение дисплея).
call STROB ; Строб ("запуск в работу").
;---> Возврат по стеку из ПП STROB
;-----------------------------------------
; Подготовка к чтению статуса состояния.
;-----------------------------------------
bsf Status,RP0 ; Переход в 1-й банк.
movlw b'11111111' ; Все выводы порта С
movwf TrisC ; работают на вход.
bcf Status,RP0 ; Переход в 0-й банк.

bsf PortB,R_W ; Установка режима чтения (R/W=1).


NO_INIT call STROB ; Строб ("запуск в работу" инструкции
; "Status Read").
;---> Возврат по стеку из ПП STROB
;----------------------------------------------
; Анализ состояний флагов BUSY и RESET.
;----------------------------------------------
nop ; "Перестраховочная" задержка в 1 м.ц.
btfsc PortC,7 ; Флаг BUSY поднят (1) или опущен (0) ?
goto NO_INIT ; Если BUSY=1 (модуль не готов к работе с
; М/К), то состояние BUSY опрашивается
; еще раз.
; Если BUSY=0 (модуль готов к работе с М/К),
; то переход на анализ состояния флага RESET.
btfsc PortC,4 ; Флаг RESET поднят (1) или опущен (0) ?
goto START ; Если RESET=1 (сброс не было), то переход

4
; на начало исполнения программы.
; Если RESET=0 (сброс был), то программа
; исполняется далее.
;-----------------------------------------
; Подготовка к работе в режиме записи.
;-----------------------------------------
bsf Status,RP0 ; Переход в 1-й банк.
clrf TrisC ; Все выводы порта С работают на выход.
bcf Status,RP0 ; Переход в 0-й банк.
bcf PortB,R_W ; Установка режима записи (R/W=0).
call STROB ; Строб ("запуск в работу").
;---> Возврат по стеку из ПП STROB
;################################################################################
; РАБОТА С ЛЕВЫМ (1-м) КРИСТАЛЛОМ.
;################################################################################
.................................
.................................

Собственно говоря, по сравнению с аналогичной инициализацией по 3-му варианту, в


данном случае, речь идет о добавлении 4-х команд (выделено красным цветом),
обеспечивающих управление выводом RES, и "убийстве" 8-ми команд, которые
оказались ненужными (команды, обеспечивающие выполнение инструкций Display OFF
и Display StartLine, а также команды анализа состояний флага ON/OFF).
Программный выигрыш, как говорится, на лицо.
В части касающейся команд, обозначенных красным цветом, по-моему, все предельно
просто.
Команда bsf PortB,4 создает условия для дальнейшего формирования стробирующего
импульса, а с помощью команд: bcf PortB,4
nop
bsf PortB,4
формируется сам стробирующий импульс с длительностью большей, чем 1 мкс.
С учетом сказанного, остальное - то же самое, о чем говорилось в предыдущем
подразделе.
Можете сравнить. Эта процедура проще, чем рассмотренная ранее.
Гонял это "сооружение" в "железе".
Все ОК. Визуально не зафиксировал ни одного сбоя инициализации графического
модуля.

Режим чтения байтов данных из оперативной памяти графического модуля

"С пылу, с жару", приспосабливаю "вышенарытое" к организации такой "нужности", как


режим чтения байтов данных из оперативной памяти графического модуля (за
компанию).
Вопрос: "Зачем это нужно"?
Ответ: в первую очередь, затем, чтобы обеспечить копирование одного или нескольких
элементов картинки из одного "места" дисплея в другое.
Это позволяет организовать визуальное сравнение элементов картинки последующего
цикла вывода данных на индикацию с элементами картинки предыдущего цикла вывода
данных на индикацию.
В том числе и с использованием простеньких "маркеров".
Вопрос: "Зачем нужно такое сравнение"?
Ответ: затем, чтобы определить расхождения.
Если речь идет о числовых результатах каких-то замеров, то практического смысла в
такой "манипуляции" нет, так как эти расхождения можно определить, банально
выделив разницу между числовыми значениями результатов замеров (эти "дела
делаются" в ПИКе).
После этого - вывод числового значения этой разницы на индикацию, и все дела.
А вот если речь идет о сравнении предыдущего и последующего, динамически
изменяющегося, "нестандартного" элемента картинки (например, эпюры), то считывание

5
этого элемента картинки (или его части), из оперативной памяти графического модуля,
может оказаться выгодным.
Это - "на вскидку".
По этому поводу, понапридумать можно много всякого, но сейчас я этим заниматься
не буду, так как, для начала, нужно "въехать в механизм" такого считывания, а только
после этого прикидывать, "к какой стенке это счастье прислонить".
Для того чтобы что-то считать из оперативной памяти графического модуля, нужно
выполнить требования таблицы 1:

Таблица 1. Инструкции, используемые при чтении данных.


Инструкции Ao R/W DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 Описание команды
Read Чтение текущего байта данных из
Data from 1 1 Байт данных, который считывается из ОЗУ выбранного столбца активной
RAM графического модуля страницы.
В конце чтения – автоинкремент.

Речь идет об инструкции Read Data from RAM. Настал ее черед.


Для того чтобы она, в дальнейшем, имела место быть, сначала, на линиях Ао и R/W
нужно выставить единицы.
Далее, нужно выбрать кристалл (в случае необходимости такого выбора), а в его
пределах - нужную страницу, а затем и нужный столбец.
Если после этой адресации к конкретному столбцу, с учетом "нижележащей'
специфики, осуществить стробирование, то после "прохождения" строба, на линях
DB7…DB0 установятся уровни битов байта того столбца, адресация к которому была
произведена ранее.
Естественно, что этот байт можно будет скопировать с выводов порта (в данном
случае, порта С) в регистр W, а потом - в регистр общего назначения.
После считывания текущего байта данных, происходит автоинкремент счетчика адреса
графического модуля, и если далее необходимо произвести считывание содержимого
следующего столбца (того, что правее), то адресовываться к нему уже не нужно.
Просто формируется следующий строб.
При этом, нужно озаботиться тем, чтобы интервал времени между двумя соседними
стробами был не менее, чем 8 мкс.
Режим чтения, по сравнению с режимом записи, имеет специфику.
Она заключается в том, что после окончания адресации к тому столбцу, байт
которого будет считываться первым, нужно произвести "пустой" цикл
чтения.
То есть, результат этого считывания "выбрасывается на помойку".
Возникает въедливый и уважаемый вопрос: "А если этого не делать, то что будет"?
Разработчики об этом - ни гу-гу ("сов. секретно").
Но русские колбки прониклись ответственностью момента.
Проверка была призведена при помощи засылки шпиона (блокировка "пустого" цикла
чтения и т.д.).
Результат: в случае игнорирования "пустого" цикла чтения, чтение массива байтов
начинается не с того столбца, к которому происходит адресация, а с того столбца,
который расположен левее.
То есть, для того чтобы устранить этот "недолет", нужен один "технологический"
автоинкремент.
Именно для обеспечения этого автоинкремента и нужен один "пустой" цикл чтения,
который нужно отработать перед считыванием первого байта массива байтов данных.
После этого, заявленная адресация будет соответствовать фактической.
Ну ладно, с "механизмом" чтения все более-менее понятно.
Предположим, что нужно считать 4 байта (можно и больше, но в данном случае, это
не принципиально важно).
Вопрос: "Куда считывать"?
Ответ: сначала в W. Это однозначно.
А потом, содержимое W нужно "заложить" в какие-нибудь "закрома", ведь регистр W
один, и он "нарасхват", а байтов аж 4.
Вопрос: "Что за закрома"?

6
Ответ: либо оперативная, либо EEPROM память ПИКа.
EEPROM память это пока "крутовато", а вот оперативная память - в самый раз.
Вопрос: "Ну скопировали. А дальше что"?
Ответ: а дальше - "все что угодно". Байты-то сохранены.
Из них можно сделать "цифровой коктейль" (в том числе и с задействованием
"сторонних" байтов, и с задействованием вообще "черт знает чего". В пределах
дозволенного), но в обучающих целях, проще всего вывести эти байты на индикацию
"по верху" какого-нибудь элемента картинки 1-го "кадра".
Факт такого вывода на индикацию будет свидетельствовать о том, что чтение прошло
успешно и усилия не потрачены зря.
В качестве того, что будет копироваться, выбран символ "1" (3-я страница 2-го
кристалла).
В качестве того, что будет "убито" записью "по верху", выбран символ "2" (4-я
страница 2-го кристалла).
Но можно придумать и что-то другое.
Оба этих символа созданы в матрице 4х7 точек.
Значит, можно обойтись копированием 4-х байтов.
Вот Вам и исходные данные.
А теперь, "шашки наголо и в атаку":

...................................
...................................

;================================================================================
; Подпрограмма чтения данных.
;================================================================================
READ_D call STROB ; Строб (инициализация чтения).
;---> Возврат по стеку из ПП STROB
movf PortC,W ; Копирование считанного байта данных в W.
return ; Возврат по стеку в то место, откуда
; произошел вызов подпрограммы.
;================================================================================
...................................
...................................

;================================================================================
; ЗАДЕРЖКА (около 2 сек.)
;================================================================================
PAUSE movlw .93 ;
movwf Mem1 ;
movlw .38 ;
movwf Mem2 ;
movlw .11 ;
movwf Mem3 ;

decfsz Mem1,F ; Стандартный


goto $-1 ; 3-байтный
decfsz Mem2,F ; вычитающий
goto $-3 ; счетчик.
decfsz Mem3,F ;
goto $-5 ;

return ; Возврат по стеку в то место, откуда


; произошел вызов подпрограммы.
;================================================================================

;********************************************************************************
; НАЧАЛО ПРОГРАММЫ.
;********************************************************************************
START
...................................
...................................

7
;--------------------------------------------------------------------------------
; Запись в 8-ю страницу 2-го кристалла
;--------------------------------------------------------------------------------
call STRANICA_8 ;
call STOLB_1 ;
movlw .64 ;
movwf Temp ;

WR_16 movf Temp,W ;


sublw .64 ;
movwf Reg ; То же самое, только
call TEXT_16 ; переход происходит
movwf PortC ; в ПП TEXT_16.
movlw high WRITE_D;
movwf PCLATH ;
call WRITE_D ;
decfsz Temp,F ;
goto WR_16 ;
;================================================================================
call PAUSE ; Задержка.
;---> Возврат по стеку из ПП PAUSE

;================================================================================
; Чтение выбранных (из 3-й страницы 2-го кристалла) байтов.
;================================================================================
; Подготовка к чтению.
;------------------------------------
call STRANICA_3 ; Выбор 3-й страницы.
movlw b'01010010' ; Выбор адреса 19-го столбца (12h).
movwf PortC ; Вывод команды выбора адреса столбца на
; линии DB7...DB0.
call STROB ; Строб ("запуск в работу").
;---> Возврат по стеку из ПП STROB
bsf Status,RP0 ; Переход в 1-й банк.
movlw b'11111111' ; Все выводы порта С
movwf TrisC ; работают на вход.
bcf Status,RP0 ; Переход в 0-й банк.

bsf PortB,A0 ; Обеспечение условия работы с байтами данных


; (A0=1).
bsf PortB,R_W ; Установка режима чтения (R/W=1).
call READ_D ; Пустой цикл чтения
;---> Возврат по стеку из ПП READ_D ; (результат не используется).
;------------------------------------
; Чтение.
;------------------------------------
call READ_D ; Текущий байт данных
;---> Возврат по стеку из ПП READ_D ; считывается
movwf Mem1 ; в регистр Mem1.

call READ_D ;
;---> Возврат по стеку из ПП READ_D ; Аналогично для Mem2.
movwf Mem2 ;

call READ_D ;
;---> Возврат по стеку из ПП READ_D ; Аналогично для Mem3.
movwf Mem3 ;

call READ_D ;
;---> Возврат по стеку из ПП READ_D ; Аналогично для Mem4.
movwf Mem4 ;
;------------------------------------
; Подготовка к дальнейшей записи.
;------------------------------------
bsf Status,RP0 ; Переход в 1-й банк.
8
clrf TrisC ; Все выводы порта С работают на выход.
bcf Status,RP0 ; Переход в 0-й банк.

bcf PortB,A0 ; Обеспечение условия работы с командами


; (A0=0).
bcf PortB,R_W ; Установка режима записи (R/W=0).
call STROB ; Строб ("запуск в работу").
;---> Возврат по стеку из ПП STROB
;================================================================================
; Запись считанных байтов в 4-ю страницу 2-го кристалла.
;================================================================================
call STRANICA_4 ; Выбор 4-й страницы.
movlw b'01010010' ; Выбор адреса 19-го столбца (12h).
movwf PortC ; Вывод команды выбора адреса столбца на
; линии DB7...DB0.
call STROB ; Строб ("запуск в работу").
;---> Возврат по стеку из ПП STROB

movf Mem1,W ; Вывод на индикацию


movwf PortC ; содержимого
call WRITE_D ; регистра Mem1.
;---> Возврат по стеку из ПП WRITE_D
movf Mem2,W ;
movwf PortC ; Аналогично для Mem2.
call WRITE_D ;
;---> Возврат по стеку из ПП WRITE_D
movf Mem3,W ;
movwf PortC ; Аналогично для Mem3.
call WRITE_D ;
;---> Возврат по стеку из ПП WRITE_D
movf Mem4,W ;
movwf PortC ; Аналогично для Mem4.
call WRITE_D ;
;---> Возврат по стеку из ПП WRITE_D

call PAUSE ; Задержка.


;---> Возврат по стеку из ПП PAUSE
;================================================================================
; "На колу мочало".
;================================================================================
goto START ; Переход на следующий цикл программы.
;================================================================================

;********************************************************************************
; Таблицы данных, предназначенных для записи.
;********************************************************************************
...................................
...................................

Работа процедуры
В "шапке" программы "прописываются" 4 регистра оперативной памяти Mem1…Mem4.
Именно в них и будет производиться считывание байтов данных из оперативной
памяти графического модуля.
Сначала нужно считать нужные байты данных.
Перед этим, нужно произвести адресацию к 1-му байту этого массива:

;================================================================================
; Чтение выбранных (из 3-й страницы 2-го кристалла) байтов.
;================================================================================
; Подготовка к чтению.
;------------------------------------
call STRANICA_3 ; Выбор 3-й страницы.
movlw b'01010010' ; Выбор адреса 19-го столбца (12h).
movwf PortC ; Вывод команды выбора адреса столбца на
9
; линии DB7...DB0.
call STROB ; Строб ("запуск в работу").
;---> Возврат по стеку из ПП STROB

Так как перед входом в данную процедуру, происходила работа во 2-м кристалле, то и
включать 2-й кристалл не нужно.

Так как далее необходимо организовать чтение байтов данных из оперативной памяти
графического модуля, то нужно к этому подготовиться:

bsf Status,RP0 ; Переход в 1-й банк.


movlw b'11111111' ; Все выводы порта С
movwf TrisC ; работают на вход.
bcf Status,RP0 ; Переход в 0-й банк.

bsf PortB,A0 ; Обеспечение условия работы с байтами данных


; (A0=1).
bsf PortB,R_W ; Установка режима чтения (R/W=1).
call READ_D ; Пустой цикл чтения
;---> Возврат по стеку из ПП READ_D ; (результат не используется).

Имеет место быть перестройка направлений работы выводов порта (порта С),
подключенных к линиям DB7…DB0, обеспечение условий исполнения инструкции Read
Data from RAM и "пустой" цикл чтения.

ПП READ_D начинается с формирования строба.


;================================================================================
; Подпрограмма чтения данных.
;================================================================================
READ_D call STROB ; Строб (инициализация чтения).
;---> Возврат по стеку из ПП STROB
movf PortC,W ; Копирование считанного байта данных в W.
return ; Возврат по стеку в то место, откуда
; произошел вызов подпрограммы.
;================================================================================

После его "прохождения", на выводах DB7…DB0, а значит и на выводах порта С,


будут присутствовать уровни битов байта данных, считанного из той ячейки
оперативной памяти графического модуля, к которой ранее была осуществлена
адресация.
Напоминаю, что перед входом в ПП READ_D, была осуществлена перестройка
направлений работы выводов порта С на работу "на вход".
Далее, этот байт банально считывается в "легендарный" регистр W.
Дело сделано. Далее - возврат по стеку.
Если имеет место быть "пустой" цикл чтения, то считанный в регистр W, "пустой"
байт, в дальнейшем, просто не используется ("погибает" после записи "по верху" того,
что нужно).

Теперь можно считывать то, что нужно:


;------------------------------------
; Чтение.
;------------------------------------
call READ_D ; Текущий байт данных
;---> Возврат по стеку из ПП READ_D ; считывается
movwf Mem1 ; в регистр Mem1.

call READ_D ;
;---> Возврат по стеку из ПП READ_D ; Аналогично для Mem2.
movwf Mem2 ;

call READ_D ;
;---> Возврат по стеку из ПП READ_D ; Аналогично для Mem3.
movwf Mem3 ;
10
call READ_D ;
;---> Возврат по стеку из ПП READ_D ; Аналогично для Mem4.
movwf Mem4 ;

Эта процедура проста как мычание коровы: 4 последовательно исполняемые операции


чтения текущих байтов данных, с таким же последовательным копированием
содержимого регистра W в соответствующие регистры оперативной памяти (Mem1…
Mem4).
Напоминаю про автоинкремент.
В данном случае, интервал времени между любыми двумя соседними стробами будет
более 8 мкс.
Ну и ладушки.

4 байта данных считаны и "лежат в закромах".


Теперь нужно озаботиться их записью в ранее определенное "место" дисплея.
Но сначала нужно обеспечить условия этой записи:
;------------------------------------
; Подготовка к дальнейшей записи.
;------------------------------------
bsf Status,RP0 ; Переход в 1-й банк.
clrf TrisC ; Все выводы порта С работают на выход.
bcf Status,RP0 ; Переход в 0-й банк.

bcf PortB,A0 ; Обеспечение условия работы с командами


; (A0=0).
bcf PortB,R_W ; Установка режима записи (R/W=0).
call STROB ; Строб ("запуск в работу").
;---> Возврат по стеку из ПП STROB

Теперь нужно озаботиться адресацией:


;================================================================================
; Запись считанных байтов в 4-ю страницу 2-го кристалла.
;================================================================================
call STRANICA_4 ; Выбор 4-й страницы.
movlw b'01010010' ; Выбор адреса 19-го столбца (12h).
movwf PortC ; Вывод команды выбора адреса столбца на
; линии DB7...DB0.
call STROB ; Строб ("запуск в работу").
;---> Возврат по стеку из ПП STROB

Кристалл переключать не нужно, так как запись происходит в "епархии" 2-го кристалла.

Теперь можно записывать:


movf Mem1,W ; Вывод на индикацию
movwf PortC ; содержимого
call WRITE_D ; регистра Mem1.
;---> Возврат по стеку из ПП WRITE_D
movf Mem2,W ;
movwf PortC ; Аналогично для Mem2.
call WRITE_D ;
;---> Возврат по стеку из ПП WRITE_D
movf Mem3,W ;
movwf PortC ; Аналогично для Mem3.
call WRITE_D ;
;---> Возврат по стеку из ПП WRITE_D
movf Mem4,W ;
movwf PortC ; Аналогично для Mem4.
call WRITE_D ;
;---> Возврат по стеку из ПП WRITE_D

Вы видите то же самое мычание коровы, только с "записывательной" спецификой:


вместо звука "Му", имеет место быть звук "Мууу".
11
Эти незамысловатые и милые каждому исконно русскому (и т.д.) сердцу звуки, наводят
на философские мысли и о скоротечности всего хорошего, и о голоштанном,
счастливом детстве, проведенном на деревенских просторах, и о своей бабуле, которая
не умела читать/писать, но умела любить.
Эх, елки-моталки, были же золотые времена… (что-то меня "занесло")
Но лучше не расстраиваться, а "внести лепту".
В том смысле, что если будет Му-Мууу-Му-Мууу-Му-Мууу-и т.д., то это будет более
соответствовать "душевному и деловому моменту", чем "реактивное" Му-Муу.
Поэтому, вместо "неодушевленного мертвяка", имеет место быть "одушевленная
закольцовка" на начало исполнения программы (goto START).
А для того, чтобы как следует "насладиться этими райскими звуками", организовано
две задержки аж по 2 секунды каждая (см. ПП PAUSE).
За это время, можно "насладиться по полной программе".
Особенно с учетом того, что копирование многократно повторяется.
То есть, можно "наслаждаться" все то время, пока питание будет
включено.
При этом, в 4-й строке 2-го кристалла, будет наблюдаться
последовательная смена элементов картинок.
"Вырезки" из этих "сценариев" Вы и видите на фотографиях слева.
Собственно говоря, изменяется только то, что находится в красном
круге, но ничто не мешает "посягнуть" и нечто большее.
Программа, в которой реализовано сказанное в этом подразделе,
называется 12864_14.asm (прилагается).
Принципиальная схема - см. рис. 1 этого подраздела.
В этой программе, я постарался как можно более доходчиво отразить суть сказанного
выше.
Естественно, что эту "базу" можно очень сильно "углубить и расширить".
Можно ли "подпрячь под это дело" косвенную адресацию?
Можно. Особенно в случаях работы с массивами байтов значительного объема.
Примечание: то количество регистров общего назначения, которое имеется, позволяет
работать с достаточно "массивными" элементами картинки.
Можно организовать работу программы не по "оптовому" принципу (как в данном
случае), а по принципу полномасштабной обработки текущего байта (побайтного
чтения/записи), но в этом случае, процедура будет более "тормозной", так как придется
много раз перестраиваться из режима в режим.
И так далее. Вариантов может быть много.
Но "база" есть "база" ("важняк").
Именно от нее и начинаются все дальнейшие "песни и пляски".
Только нужно не путать "базу" с ее "производными".
Практически любую "базу" можно ругать. И ругать обоснованно.
Но от этого она не становится менее значимой.
Это как таблица умножения.
С точки зрения математика, формально, это примитив, но настоящий математик
(купленные дипломы и звания не в счет), имеющий совесть, никогда и ни при каких
обстоятельствах не позволит себе неуважительного к ней отношения, так как именно
таблица умножения и сделала его математиком.
В соответствии с этой "концепцией", то, чем мы с Вами сейчас занимаемся, вовсе не
есть ерунда.
На основе этой "ерунды", можно "наваять" такое, что у "непосвященных челюсть
отвиснет".
Особенно с учетом того, что речь идет о таких достаточно "крутых железяках", как
графические модули.

"Промежуточный" итог: на данный момент, "расписаны" все инструкции графического


модуля.
Это означает то, что в наличии имеется некий "инструментарий", необходимый для
дальнейшей, максимально осмысленной работы.

"Практикум по конструированию устройств на PIC контроллерах"      http://ikarab.narod.ru       E-mail: karabea@lipetsk.ru

12
13