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

2/1.

"Нейрохирургическая операция" ("на молекулярном уровне") по


записи в "пустые мозги" одного байта данных. Детальное
объяснение.

Итак, "артподготовка" закончилась и можно "двигать войска в атаку" (сейчас "прольется чья-то
кровь" ...).
"Атаковать" буду в порядке ранее выработанного "расстрельного списка".
В соответствии с ним, первой в очереди стоит запись в 24С64А одного байта данных.
Для начала, чтобы иметь перед собой какой-то ориентир, нужно изучить "опыт боевых
действий".
Просматриваю имеющиеся у меня, по этой теме, тексты программ, после чего "волосы
потихоньку начинают шевелиться".
Приходится в очередной раз констатировать тот факт, что то, что нам предлагается,
совсем далеко от совершенства: не программы, а какие-то "монстры".
А именно: программного "мусора" "выше крыши" (соответственно, большое количество
команд), несоразмерно затянуты задержки, при помощи которых обеспечивается
соблюдение предельных временных характеристик, нерациональные конструкции
программ и т.д.
Что означает, аналогичная требуемой, программа записи одного байта объемом около
120-ти команд?
А означает это форменное безобразие.
Забегая вперед, скажу, что в 1-м варианте моей программы всего 60 команд, а во 2-м
варианте - 52.
Тексты программ максимально "скомпрессированы" и, на мой взгляд, не содержат
ничего лишнего.
Соблюдение требований предельных временных параметров (в пределах требований к
временным характеристикам программ) обеспечено.
Программы проверены в работе и работают четко.
"До жизни такой я докатился" при помощи "плевка" в сторону предлагаемого
"ширпотреба", так как мне легче "сваять" программу "с нуля", чем тратить время и нервы
на "плутания в лабиринтах" чьих-то не вполне рациональных (на мой взгляд) замыслов.
Для начала, "привяжусь" к предельным временным параметрам концепции I2C.
Итак, о чем идет речь?
Речь идет об учебной программе записи одного байта данных.
А посему, эта программа одноцикловая: в конце 1-го полного цикла программы, для
того чтобы предотвратить многократную запись "по верху", рабочая точка программы
"уходит" в "мертвое, вечное кольцо" вплоть до выключения питания.
Если убрать из текста программы подпрограмму "мертвого, вечного кольца", то эту
программу, в "статусе" подпрограммы, можно "врезать" (с учетом специфики) в какую-
то "материнскую" программу.
Естественно, затевать весь этот "сыр-бор", из-за одного байта, не стоит (можно обойтись
EEPROM памятью ПИКа), но программа записи одного байта является "матерью"
программ записи нескольких байтов (в том числе и поточной записи большого массива
байтов), плюс, часть ее используется при чтении, а это уже "важняк".
А раз это так, то в учебную программу записи в 24С64А одного байта данных, нужно
"въехать" на полном серьезе и детальнейшим образом.
Программа называется Write_1.asm.

1
;********************************************************************************
; Write_1.asm ЗАПИСЬ В 24С64А ОДНОГО БАЙТА ДАННЫХ (учебная, одноцикловая ;
программа). Анализ состояний флага АСК осуществляется в ПП
; "плавающей" задержки.
;********************************************************************************
; "Практикум по конструированию устройств на PIC контроллерах".
; Автор: Корабельников Евгений Александрович
; http://ikarab.narod.ru karabea@lipetsk.ru
; Эта программа входит в состав 1-го подраздела 2-го раздела.
;********************************************************************************
; "Мастер" - PIC16F84A.
; "Помощник" - 24C64A.
; Кнопка пуска записи подключена к выводу RB0.
; Светодиод (индицирует конец цикла записи) подключен к выводу RB1.
; Вывод RB6 подключен к линии такта (SCL).
; Вывод RB7 подключен к линии данных (SDA).
; Кварц 4 Мгц. (1м.ц.=1мкс.).
; Объем программы: 60 команд.
;********************************************************************************
LIST p=16F84A ; Установка типа микроконтроллера.
__CONFIG 03FF5H ; Бит защиты выключен, WDT включен,
; стандартный XT - генератор.
;================================================================================
; Определение положения регистров специального назначения.
;================================================================================
OptionR equ 01h ; Регистр OptionR - 1-й банк.
Status equ 03h ; Регистр выбора банка.
TrisB equ 06h ; Регистр TrisB - 1-й банк.
PortB equ 06h ; Регистр управления защелками порта В.
;================================================================================
; Определение названий и положения регистров общего назначения.
;================================================================================
Temp equ 0Ch ; Регистр, в котором происходит сдвиг.
Count equ 0Dh ; Счетчик битов байта.
;================================================================================
; "Привязка" названий битов регистров специального назначения к номерам битов.
;================================================================================
RP0 equ 5 ; Бит выбора банка.
C equ 0 ; Бит флага переноса-заёма.
SCL equ 6 ; Бит регистра PortB, который формирует такт.
SDA equ 7 ; Бит регистра PortB, который формирует данные
;================================================================================
; Определение места размещения результатов операций.
;================================================================================
F equ 1 ; Результат направить в регистр.
W equ 0 ; Результат направить в аккумулятор.
;================================================================================
org 0 ; Начать выполнение программы с нулевого
; адреса PC.
;********************************************************************************

2
;********************************************************************************
; "РАБОЧАЯ ЧАСТЬ" ПРОГРАММЫ.
;********************************************************************************
; Подготовительные операции.
;================================================================================
bsf Status,RP0 ; Переход в 1-й банк.
movlw b'00000001' ; RB0 (к нему подключена кнопка) работает "на
movwf TrisB ; вход", остальные RB... работают на выход.
movlw b'01111101' ; Предделитель с Кдел.=32 подключен к выходу
movwf OptionR ; WDT, подтягивающие резисторы порта В
; включены.
bcf Status,RP0 ; Переход в 0-й банк.
movlw b'11000000' ; На линиях SDA и SCL выставляются единицы,
movwf PortB ; светодиод погашен.

;---------------------------------------------------------
; Ожидание нажатия кнопки.
;---------------------------------------------------------
KNOPKA_NO clrwdt ; Сброс WDT.
btfsc PortB,0 ; Если кнопка отжата, то уход в
goto KNOPKA_NO ; "вечное кольцо" ПП KNOPKA_NO.
; Если кнопка нажата, то программа
; исполняется далее.

;********************************************************************************
; ПРОЦЕДУРА ЗАПИСИ
;********************************************************************************
; Формирование старт-условия.
;================================================================================
bcf PortB,SDA ; SDA=0.
goto $+1 ; Задержка на 2 мкс.
nop ; Задержка на 1 мкс.
bcf PortB,SCL ; SCL=0.

;================================================================================
; "Администраторская" ПП (без названия), "рулящая" очередностью обработки байтов.
;================================================================================
; Задание числового значения режимного байта.
;---------------------------------------------------
movlw B'10100000' ; Запись в регистр Temp режимного байта
movwf Temp ; (1010- код функциональности, 000–адрес
; м/схемы, 0–режим записи).
call BAIT_WR ; Условный переход в ПП обработки байта
; BAIT_WR.
;-----> Возврат по стеку из ПП BAIT_WR.
;---------------------------------------------------
; Задание числового значения старшего байта адреса.
;---------------------------------------------------
movlw .0 ; Запись в регистр Temp
movwf Temp ; старшего байта адреса.
call BAIT_WR ; Условный переход в ПП обработки байта

3
; BAIT_WR.
;-----> Возврат по стеку из ПП BAIT_WR.

;---------------------------------------------------
; Задание числового значения младшего байта адреса.
;---------------------------------------------------
movlw .2 ; Запись в регистр Temp
movwf Temp ; младшего байта адреса.
call BAIT_WR ; Условный переход в ПП обработки байта
; BAIT_WR.
;-----> Возврат по стеку из ПП BAIT_WR.
;---------------------------------------------------
; Задание числового значения байта данных.
;---------------------------------------------------
movlw .47 ; Запись в регистр Temp байта данных,
movwf Temp ; предназначенного для записи (2Fh).
call BAIT_WR ; Условный переход в ПП обработки байта
; BAIT_WR.
;-----> Возврат по стеку из ПП BAIT_WR.

;================================================================================
; Формирование стоп-условия.
;================================================================================
bcf PortB,SDA ; SDA=0.
nop ; Задержка на 1 мкс.
bsf PortB,SCL ; SCL=1.
goto $+1 ; Задержка на 2 мкс.
nop ; Задержка на 1 мкс.
bsf PortB,SDA ; SDA=1.

;================================================================================
; Завершение полного цикла программы.
;================================================================================
bsf PortB,1 ; Светодиод "загорелся".
clrwdt ; Сброс WDT.
goto $-1 ; Уход в "мертвое", "вечное кольцо" до
; выключения и последующего включения питания.

;********************************************************************************
; Подпрограмма обработки байта.
;********************************************************************************
BAIT_WR movlw .8 ; Запись в счетчик битов количества
movwf Count ; битов в одном байте.
;================================================================================
; Обработка текущего бита
;================================================================================
SNOVA rlf Temp,F ; Циклический сдвиг влево. Этим обеспечивается
; обработка битов байта, начиная с бита
; старшего разряда (№7...№0).
bcf PortB,SDA ; SDA=0.
btfsc Status,C ; Что "ушло" в бит С?
bsf PortB,SDA ; Если в бите С 1, то SDA=1.
nop ; Задержка 1 мкс.
bsf PortB,SCL ; SCL=1. (Если в бите С 0, то SDA=1 не

4
; исполняется. Вместо нее – "виртуальный" NOP)
nop ; Задержка 1 мкс.
goto $+1 ; Задержка 2 мкс.
bcf PortB,SCL ; SCL=0.
decfsz Count,F ; Декремент счетчика битов (Count-1=...).
goto SNOVA ; Если результат не=0, то переход на обработку
; следующего бита.
goto $+1 ; Если результат =0, то обработка байта
; закончена, после чего - задержка на 2 мкс.

;********************************************************************************
; Группа команд формирования импульса 9-го такта и анализа состояний флага АСК.
;********************************************************************************
; Начало формирования импульса 9-го такта.
;--------------------------------------------------------------------------------
bsf PortB,SCL ; Формируется строб (перепад от 0 к 1)
; импульса 9-го такта.
;--------------------------------------------------------------------------------
; Подготовка к анализу состояний флага АСК (перестройка направления работы
; вывода RB7).
;--------------------------------------------------------------------------------
bsf Status,RP0 ; Переход в 1-й банк.
bsf TrisB,SDA ; Вывод SDA работает на вход.
bcf Status,RP0 ; Переход в 0-й банк.

;================================================================================
; Анализ состояний флага АСК ("плавающая" задержка).
;================================================================================
ACK btfsc PortB,SDA ; На линии SDA 0 или 1 ?
goto ACK ; Если 1, то снова анализ (задержка до
; появления 0).
;--------------------------------------------------------------------------------
; Конец формирования импульса 9-го такта.
;--------------------------------------------------------------------------------
bcf PortB,SCL ; Если 0, то формируется спад импульса
; 9-го такта.
;--------------------------------------------------------------------------------
; Обратная перестройка направления работы вывода RB7.
;--------------------------------------------------------------------------------
bsf Status,RP0 ; Переход в 1-й банк.
bcf TrisB,SDA ; Вывод SDA работает на выход.
bcf Status,RP0 ; Переход в 0-й банк.

return ; Возврат по стеку в "администраторскую" ПП.

;********************************************************************************
end ; Конец программы.

5
Принципиальная схема устройства (под программу Write_1.asm) очень простая и "ваяется на
коленке" за считанные минуты.
Сразу бросается в глаза отсутствие внешних, подтягивающих резисторов на линиях SCL и
SDA. С SCL все понятно (об этом говорилось ранее), а вот с SDA - ???
А "ларчик просто открывается": в предыдущих подразделах, объяснение было
ориентировано на порт А, не имеющий внутренних подтягивающих резисторов.
Если линии SCL и SDA подключить к выводам порта В, имеющего внутренние
подтягивающие резисторы, а в подготовительных операциях ПП START включить
подтягивающие резисторы, то, кроме "избавления" от внешнего подтягивающего
резистора линии SDA, происходит также и "избавление" от внешнего подтягивающего
резистора кнопки (если кнопка подключена к выводу порта В), что Вы и видите.
После включения питания и исполнения подготовительных операций ПП START,
рабочая точка программы "закольцовывается" в "вечном кольце" ПП ожидания нажатия
кнопки, вплоть до ее нажатия ("Пуск записи").
После нажатия кнопки "Пуск записи", произойдет запись заранее заданного числового
значения байта в заранее заданную ячейку памяти 24С64А.
Подставляя в текст программы другие значения соответствующих констант, можно задать
как произвольный адрес ячейки памяти, так и произвольное числовое значение
записываемого в нее байта (естественно, в пределах дозволенного).
По умолчанию, в программе выбрана ячейка с адресом 02h, и в нее записывается байт с
числовым значением 2Fh. После окончания записи, "загорится" светодиод "Окончание
записи", а рабочая точка программы будет "мотать круги" в ПП "вечного, мертвого
кольца".
Слово "мертвого" означает то, что ни одним внешним воздействием, кроме выключения
(и последующего включения) питания, вывести рабочую точку программы, из этой
"мертвой закольцовки", не возможно.
Обращаю Ваше внимание на то, что данное проверочное устройство не реализует
функцию индикации записываемого (или записанного), в ячейку памяти, числа, что
конечно же, не удобно, но не смертельно. Для выхода из этого "ступора", нужно
задействовать PonyProg (или другой программатор, поддерживающий PIC16F84A и

6
24С64А).
Я использовал русскую версию PonyProg. Порядок работы выглядит так:
1. Настраиваете PonyProg на 24С64А (в левом окошке - "I2C Bus 16bit eeprom", в
правом окошке - 2464/2465).
2. Производите считывание. То, что считается, не важно. Нас интересует только ячейка
памяти с адресом 02h.
3. Теперь нужно записать в ячейку памяти с адресом 02h какое-нибудь число, отличное
от 2Fh (чтобы, в дальнейшем, можно было проверить факт записи числа 2Fh).
Я записывал 00h. Для этого: "Правка" - "Редактирование буфера".
Затем щелкаете левой кнопкой мыши по числовому значению байта, расположенному по
адресу 02h и в окне "Редактировать буфер" убираете "старое" числовое значение байта
(в самом верхнем окошке) и вместо него "настукиваете" 00. Жмете "ОК".
После этого, в ячейке с адресом 02h Вы увидите число 00 (00h).
4. Теперь, при помощи PonyProg, нужно обычным образом, записать в 24С64А
содержимое отредактированного буфера.
5. После этого, в том же PonyProg, можно стандартно считать данные из памяти 24С64А
и убедиться, что по адресу 02h записалось число 00h (это не обязательно).
6. Вставляете 24С64А в панельку проверочного устройства, включаете питание и
кратковременно жмете кнопку "Пуск записи". После "загорания" светодиода,
сигнализирующего об окончании цикла записи, выключаете питание и вставляете
24С64А в панельку программатора.
7. Теперь, в PonyProg, нужно произвести стандартное считывание и убедиться в том, что
число 00h, по адресу 02h, заменилось на число 2Fh, что и есть показатель успешной
записи.
Если, в проверочном устройстве, нужно произвести еще один цикл записи, в том числе и
после изменения, в тексте программы, адреса ячейки и значения записываемого байта
(относительно установленных по умолчанию), то нужно повторить все 7 пунктов.
Это конечно-же "не Рио-де-Жанейро", но, в данном случае, по-другому нельзя (искусство
требует жертв).
А теперь одно очень существенное, "глобальное" замечание.
При составлении программы Write_1.asm (и подобного рода программ), имеет место
быть совсем "не хилая" и "скользкая" работа с фазой.
При этом возникает "бардальеро" с понятиями "фазовый сдвиг" и "задержка", связанное с
"взаимопроникновением" одного в другое. Давайте наводить порядок.
Если речь идет о программах для м/контроллеров, то понятие "задержка" является
"суперглобальным" (основополагающим), так как выполнение любой команды
программы уже есть задержка. Так можно ставить знак равенства между задержкой и
фазовым сдвигом?
Нет, нельзя, по той простой причине, что фазовый сдвиг имеет место быть (причем, в
любом случае, так как одномоментно несколько команд выполняться не могут) только
в случае формирования 2-х (и более) импульсных последовательностей.
В рассматриваемом случае, фазовый сдвиг имеет место быть, так как имеются две
импульсные последовательности (на линии SCL и линии SDA). К ним и "привяжусь".
Если речь идет об одной импульсной последовательности, то никакого фазового сдвига
нет (сдвиг импульсной последовательности, относительно самой себя, есть абсурд).
Вывод: задержки имеют место быть в обеих случаях, но о фазовом сдвиге речь идет
только в 1-м случае. Это и есть главная причина, по которой нельзя полностью
отождествлять понятия "задержка" и "фазовый сдвиг".
Итак, имеются две импульсные последовательности, которые, уже по определению (по
логике работы любой программы), будут сдвинуты (во времени) относительно друг

7
друга.
Та импульсная последовательность, перепад которой, по ходу исполнения программы,
формируется первым, будет, по фазе, опережать импульсную последовательность,
перепад которой, по ходу исполнения программы, формируется вторым.
Далее "вскакивает" хитрющий вопрос о величине фазового сдвига.
Можно ли утверждать, что величина фазового сдвига полностью определяется временем
задержки одной импульсной последовательности относительно другой?
Нет, нельзя, так как величина фазового сдвига есть отношение периода к величине
задержки, да еще и выраженная в градусах.
Говорить о какой-то фиксированной величине фазового сдвига удобно только в случаях
формирования равномерных импульсных последовательностей (с одинаковым
периодом и фиксированной скважностью).
А как быть с м/контроллерами, ведь кроме формирования импульсных
последовательностей, нужно сделать еще "кучу разных дел" (например,
подготовительные операции и т.д.), а сразу несколькими "делами они заниматься не
могут"?
Именно отсюда и "растут ноги" того, что я называю "рваной (гуляющей) фазой" (это моя
фантазия).
При работе с м/контроллерами, если программа многофункциональна (а это имеет
место быть в большинстве программ), равномерные импульсные последовательности
можно сформировать только в виде "пачек" импульсов, и только в пределах
формирующей их циклической (многоцикловой, то есть, "поставленной на счетчик")
подпрограммы, да и то не всегда. Во всех остальных случаях, величина фазового сдвига
будет "гулять" (меняться) и это, естественно, порждает понятийный "бардак".
Лично я, нашел для себя следующий выход из положения: на понятии "величина
фазового сдвига", поставил "большой и жирный крест" и заменил его на более
"удобоваримое" понятие "фазовая задержка".
Это понятие, хотя, точно и не отражает величины фазового сдвига (да еще и в градусах),
но, в общем виде (без указания величины фазового сдвига), отражает "жесткую
привязку" задержки к фазе.
То есть, фазовый сдвиг "привязывается" не к градусам, а к фиксированным величинам
задержек (к машинным циклам), что есть "зер гут".
После этого, все встало на свои места.
Примечание: я вовсе не навязываю Вам своей "концепции" "въезда" в фазу (можете
придумать и что-то свое, каждый думает так, как ему удобно), а только делюсь опытом
и пытаюсь дать представления о специфике работы с фазой, в части касающейся
м/контроллеров.
Обратите внимание на то, что я сказал "к фиксированным величинам задержек" (во
множественном числе).
Это означает то, что, наряду со случаями применения фиксированных задержек одной
величины, имеют место быть (и очень часто) случаи применения фиксированных
задержек других величин ("набора").
Например, перепад 1-го импульса импульсной последовательности №2 задержан
относительно перепада 1-го импульса импульсной последовательности №1, на 5 м.ц.
(имеются ввиду перепады, относительно которых осуществляется отсчет величины
фазовой задержки в машинных циклах), а следующий перепад 2-го импульса
импульсной последовательности №2 задержан относительно перепада 2-го импульса
импульсной последовательности №1, на 8 м.ц. и т.д., вплоть до того, что, при
формировании фазовых сдвигов между соответствующими перепадами обеих
импульсных последовательностей, может быть использована целая "куча"

8
"разнокалиберных" (по величине) фиксированных задержек.
Означает ли это то, что будет иметь место быть "куча" подпрограмм задержек и,
соответственно, куча переходов в них и возвратов из них?
Нет, не означает, так как фиксированные задержки, о которых идет речь, очень
короткие, и они формируются либо за счет "рабочих" команд (совмещение функций
"рабочего" действия и задержки), либо за счет NOPов (или goto $+1).
Последнее применяется в случае необходимости "наращивания" величины задержки до
величины не менее заданной.
Слово "заданной" есть "граница" ("планка", "межа" и т.д.), которую "переступать" нельзя.
Это означает то, что величина любой фиксированной задержки (в пределах этой
"однофункциональной кучи") не должна быть меньше, оговоренного в технической
документации, соответствующего, временного "зазора" (из списка предельных,
временных параметров).
Больше - ради Бога. Меньше - могут быть неприятности.
Например, в соответствии с предельными, временными параметрами концепции
интерфейса I2C, величина времени формирования уровня единицы на линии SCL
должна быть больше или равна 4 мкс.
Это означает то, что суммарное время исполнения всех команд, участвующих в
формировании импульса (от смены 0 на 1 до смены 1 на 0) должна быть больше или
равна 4 мкс. Словосочетание "всех команд" следует понимать в буквальном смысле
(смысл этого предложения будет понятен ниже).
Суть формирования фазового сдвига точно такая же, только с "оглядкой" на ту
импульсную последовательность, относительно которой происходит фазовый сдвиг (ту,
которая опережает по фазе. Она, как бы, является "точкой отсчета").
Вот такой, в сущности, незамысловатый "расклад".
Таким образом, в части касающейся линий SCL и SDA (и не только), работа с фазой
сводится к формированию, на линии SCL, фиксированных задержек (и за счет "рабочих"
команд, и за счет NOPов или oto g $+1), с суммарной величиной равной или
превышающей соответствующее значение предельного временного параметра.
Естественно, в этом случае, перепады на линии SDA должны опережать (по фазе или по
времени: можно и так и эдак) "привязанные" к ним перепады на линии SCL.
При этом, в общем виде, признается факт работы с "рваной фазой" (так как суммарные
задержки могут быть различной величины), и не более того.
И никаких тебе "неудобоваримых" соотношений периода к задержке, градусов и прочих
фазовых "бяк".
Все это я говорю не просто так, а с целью Вашей подготовки к восприятию того, что Вы
увидите ниже.
А ниже Вы увидите, на первый взгляд, "страшные и ужасные" картинки, с множеством
всяких "штучек".
Просьба не "пугаться", так как имеет место быть детальнейшая "разрисовка" процедуры
записи одного байта данных в 24С64А, которая, и я абсолютно уверен в этом, в таком
крайне "разжеванном" виде, предлагается впервые.

9
Сразу объясню, что такое, в моем понимании, "рваная фаза".
Найдите на рис. 2А тактовые импульсы №№1 и 2.
Тактовый импульс №1 сформирован под бит=1, а тактовый импульс №2 сформирован
под бит=0.
Задержка Тз строба 1-го тактового импульса, относительно фронта бита №7, составляет
2 м.ц., а задержка Тз строба 2-го тактового импульса, относительно спада бита №7,
составляет 4 м.ц.
Заданное мной условие, по величине Тз, звучит так: величина Тз должна быть равна
или более 2-х м.ц. (2 мкс.).

10
В обеих случаях, это условие соблюдается.
Вот Вам и "рваная фаза", наличие которой объясняется тем, что время формирования (на
линии SDA) бита с уровнем 1 (11 м.ц.) меньше времени формирования бита с уровнем 0
(15 м.ц.).
Таким образом, при формировании всех битов байта с уровнем 1, Тз = 2 м.ц., а при
формировании всех битов байта с уровнем 0, Тз = 4 м.ц.
Эта разница объясняется конкретной конструкцией подпрограммы обработки битов
байта, а именно, наличием в ней двухсценарной проверки состояния флага С (btfsc
Status,C).
"Смертельна-ли" эта "рваная фаза"?
Если соблюдены требования предельных временных параметров (а они соблюдены), то
не в коем разе.
Что касается линии SCL, то, в пределах многоцикловой подпрограммы обработки битов
байта, формируется равномерная, импульсная последовательность (8 импульсов) со
скважностью, отличной от "меандра".
Что касается линии SDA, то "протяженность" (во времени) битов будет зависеть от их
значения (0 или 1).
Конечно же, можно "подсуетиться" и "забацать", на линии SCL, "меандр", но зачем
нужен этот совершенно лишний "геморрой"?
Таким образом, если речь идет о многоцикловых ПП минимального объема,
вырабатывающих две (и более) "фазово привязанные" друг к другу импульсные
последовательности, то, на практике, редко когда удается (разве только в простых
случаях) программно сформировать сигналы (или даже один сигнал) типа "меандр" и
получить "не рваную фазу".
В данном же случае, когда речь идет о достаточно "навороченных" фазовых "привязках",
"рваная фаза" это нормальное "явление", которое будет иметь место быть и далее, вплоть
до конца программы.
Для устройств на м/контроллерах, это абсолютно нормально и к этому сразу нужно
привыкать.
Что касается практики, то про "равномерные, эпюрные заборы" типа тех, которые были
предоставлены Вашему вниманию на стадии "въезда" в теорию, можно "забыть" (в
кавычках!).
Они хороши только на этой стадии, и не более того.
Если подвести итог сказанному, то "рваная фаза" ("разброс" величин
"однофункциональных", фиксированных задержек, см. выше) является специфической
особенностью подпрограмм, формирующих "фазово привязанные" друг к другу
импульсные последовательности.
Это объясняется как наличием команд ветвления (а соответственно, и различных
сценариев, которые могут исполняться за разное время), так и команд
подготовительных операций (например, перестройка направления работы вывода порта,
запись константы, переходы, возвраты и т.д.), которые, как слово, из песни не выкинешь
(иначе песня "даст дуба").
Программными средствами, этот "разброс" можно только минимизировать (естественно,
не в ущерб качеству), что я и постарался сделать в предоставленной Вашему вниманию
учебной программе.

Работа программы Write_1.asm

За ходом объяснения можно следить как по тексту программы, так и по рис. 2.


По рис. 2 это даже удобнее (специально, ради этого, над ним "попыхтел"), так как четко

11
видны "привязки" команд к тому, что "творится" на линиях SCL и SDA.
Сразу обращаю Ваше внимание (напоминаю) на то, что команды исполняются в
конце машинного цикла (команды, требующие для исполнения 2 м.ц.,
исполняются в конце 2-го м.ц.), что Вы и видите на рис. 2.
В конце "шапки" программы нет команды goto Start, так как ПП Start начинается с
нулевого адреса PC ("пинок" не нужен).
По этой же причине, а также и по причине отсутствия переходов в ПП Start, имеет
место быть ПП Start без своего названия.
Кто желает, тот может "настукать", в тексте программы, это название.
В "Подготовительных операциях", "начинка" ПИКа "конфигурируется" следующим
образом:

1. Вывод RB0 (к нему подключена кнопка пуска записи) настраивается на работу "на
вход". Остальные выводы порта В настраиваются на работу "на выход" (с целью
дальнейшего обеспечения работы по линиям SCL и SDA).
2. По причине, указанной ранее, к выводам порта В подключаются внутренние
подтягивающие резисторы (напоминаю, что они подключаются только к выводам порта
В, работающим "на вход").
В данной программе, я задействовал сторожевой таймер и подключил к нему
предделитель с Кдел=32 (время срабатывания 18х32=576 мс.).
Соответствующие настройки Вы и видите.
3. Далее имитируется ждущий режим, то есть, на линиях SCL и SDA выставляются
единицы.
Светодиод переводится в пассивное состояние (на RB1 - ноль).
На этом подготовка заканчивается.

Можно было бы еще и запретить все прерывания, но они и без этого запрещены (по
умолчанию).
Далее, рабочая точка программы переходит в ПП ожидания нажатия кнопки пуска
записи, в которой уходит в "вечное кольцо" ПП KNOPKA_NO (если кнопка отжата),
вплоть до нажатия кнопки.
После нажатия кнопки, рабочая точка программы "вырывается" из "вечного кольца" на
"оперативный простор" и начинается формирование старт-условия.
Напоминаю, что необходимый для этого ждущий режим (на линиях SCL и SDA
выставлены единицы), был установлен ранее.
Общее замечание: в целях минимизации количества команд программы, здесь и далее,
в качестве задержки на 2 м.ц., использована команда goto $+1.
Старт-условие это перепад от 1 к 0 на линии SDA, при наличии надежно
зафиксировавшейся 1 на линии SCL.
1 на линии SCL зафиксировалась, как говорится, "дальше некуда", а посему, можно
сразу же устанавливать на линии SDA ноль (bcf PortB,SDA).
Далее, в соответствии с требованиями предельных, временных параметров концепции
I2C, между спадами на линиях SDA и SCL, нужно сформировать задержку величиной
не менее 4 мкс. (включительно).
Я сформировал задержку в 4 мкс. (см. рис. 2А). Она состоит из фиксированной
задержки в 3 мкс. (goto S+1 и nop), плюс задержка команды bcf PortB,SCL.
Вот и все старт-условие. Как говорится, простенько и со вкусом.
Далее, начинается исполнение "администраторской" ПП (без названия, так как
переходов на нее нет), функция которой - "выстраивание очереди" из обрабатываемых
байтов, в порядке, определяемом алгоритмом записи в 24С64А одного байта данных:

12
режимный байт, старший байт адреса, младший байт адреса, байт данных .
Принцип работы со всеми этими байтами один и тот же: сначала в регистр Temp
записывается байт с соответствующим числовым значением, и далее он "отправляется"
(переход по стеку) на обработку в ПП обработки байта BAIT_WR (call BAIT_WR).
После окончания "всех дел" в ПП BAIT_WR и возврата по стеку в "администраторскую"
ПП, все повторяется снова, только с другим числовым значением байта.
По-моему, в этом нет ничего сложного.
А вот дальше, сложнее.
Раз уж первым обрабатывается режимный байт, то на рис. 2 я и "разложил на
молекулы" все то, что с ним связано.
Итак, выводим в 24С64А режимный байт.
ПП обработки байта BAIT_WR представляет собой многоцикловую ПП побитной
обработки байта, следовательно, количество ее полных циклов нужно "поставить на
счетчик".
В качестве такового используется простейший, одноразрядный, вычитающий счетчик,
производящий анализ содержимого регистра Count, работа которого "разжевана" в
"Самоучителе..." по самые ...
А раз это так, то, "на подлете" к точке входа в полный цикл ПП BAIT_WR (до метки
SNOVA), нужно записать в регистр Count число количества битов в байте (8), что Вы и
видите.
Далее это число будет последовательно декрементироваться, вплоть до окончания
обработки байта.
Обработка бита начинается с его "выпихивания" в бит С регистра Status.
А так как нужно "выпихивать" биты байта, начиная с бита самого старшего двоичного
разряда (№7), то нужно применить команду rlf.
Сдвигается содержимое регистра Temp, так как, в "администраторской" ПП, именно в
него записалось числовое значение текущего, обрабатываемого байта.
В данном случае, текущим является режимный байт с числовым значением 1010 0000,
следовательно, на 1-м "витке" полного цикла ПП BAIT_WR, в бит С регистра Status
"выпихнется" бит №7, значение которого = 1.
Далее выполняется команда bcf PortB,SDA (SDA=0).
Зачем она нужна, ведь происходит подтверждение ранее установленного состояния
(нуля после старт-условия)?
Ответ: в случае обработки единицы, эта команда пассивна в том смысле, что не
формирует перепада на линии SDA (просто задержка в 1 м.ц.).
Она становится активной в случае обработки нуля, если предшествующий бит имел
значение 1.
Это произойдет при обработке следующего бита (как раз тот случай), а пока иду дальше.
Далее следует стандартная проверка состояния бита С, с ветвлением.
В данном случае, когда в бите С "лежит" 1, исполняется команда bsf PortB,SDA и на
линии SDA формируется перепад от 0 к 1 (начало формирования единичного уровня на
линии SDA).
Второй сценарий: если в бите С "лежит" 0, то команда bsf PortB,SDA игнорируется, а
вместо нее исполняется "виртуальный NOP", а проще говоря, ноль на линии как был
нулем, так им и останется (на момент исполнения команды btfsc Status,C, на линии
SDA всегда присутствует 0).
Второй сценарий "вступит в работу" при обработке следующего бита (№6), а пока
продолжу "толковище" по биту №7.
Итак, после формирования на линии SDA уровня 1, нужно сформировать, под
"рожденный" бит, строб импульса 1-го такта, и причем, с задержкой Тз.

13
В данном случае, я задал Тз = 2 м.ц. (2 мкс.).
С учетом того, что перевод состояния линии SCL с 0 на 1 (bsf PortB,SCL) требует
одного м.ц., между командами bsf PortB,SDA и bsf PortB,SCL, нужно "врезать"
фиксированную задержку в 1 м.ц. (nop), что Вы и видите.
Примечание: в принципе, можно обойтись и без этого NOPа (программа четко
работает, проверял).
Сделал я это из "перестраховочных" соображений.
В дальнейшем, я его (и не только его) "убью".
Итак, строб 1-го такта сформирован, и причем, он сформирован в момент
гарантированно надежной установки на линии SDA уровня текущего бита (в данном
случае, единицы).
Теперь пришла пора соблюсти требования по предельным параметрам концепции I2C
(на рис. 2 указаны в скобках), в части касающейся длительности единичного уровня
тактового импульса.
Задаю его равным 4 м.ц. (4 мкс.).
Следовательно, с учетом одного м.ц. на исполнение последующей команды установки
на линии SCL нуля (bcf PortB,SCL), между командами bsf PortB,SCL и bcf PortB,SCL,
нужно сформировать фиксированную задержку в 3 м.ц., что Вы и видите (nop и goto $
+1).
Итак, "формальности" соблюдены и формирование, на линии SCL, импульса 1-го такта
закончено.
Теперь можно переходить к обработке следующего бита (№6), но перед этим нужно
декрементировать содержимое регистра Count, что и имеет место быть (decfsz
Count,F).
Далее следует переход на обработку бита №6 (goto SNOVA) и все повторяется.
Но в данном случае, в бит С регистра Status "уйдет" не 1, а 0.
Что изменится?
Во-первых, "вступит в работу" ранее пассивная команда bcf PortB,SDA (та, которая
после команды rlf Temp,F).
Она-то и завершает формирование, на линии SCL, уровня единицы бита №7.
После проверки состояния бита С (btfsc Status,C), "в работу вступает" не 1-й, а 2-й
сценарий (об этом, см. выше) и вместо команды установки на линии SCL единицы,
исполняется "виртуальный NOP".
Далее, все то же самое.
Вопрос: "Каковы последствия"?
Ответ - на рис. 2А: при обработке бита с числовым значением 0 (по сравнению с
обработкой бита с числовым значением 1) Тз увеличилось на 2 мкс. (Тз = 4 мкс.).
Вот Вам и "рваная фаза" во всей своей "боевой раскраске".
Еще раз обращаю Ваше внимание на то, что ничего "страшного" в "рваной фазе" нет, так
как "микроконтроллерная специфика" диктует свои "правила игры", которые нужно
принять как данность.
Удобств конечно маловато, но "бытие определяет сознание", и хочешь - не хочешь, но в
это "бытие" "вписываться" нужно (а куда деваться?).
Теперь нужно проверить соблюдение условия: время формирования нулевого уровня на
линии SCL должно быть более или равно 5 мкс.
Соблюдено?
Так точно, и с запасом (9 мкс.).
Это значение можно уменьшить на 1 мкс., но не более того.
Ничего из остального не выкинешь. Все требуется (в приложении к концепции I2C).
Что дальше?

14
А дальше все то же самое (с учетом того, что обрабатывается, 0 или 1), вплоть до
окончания обработки бита №0.
После этого, содержимое счетчика битов обнуляется и, после задержки на 2 м.ц. (goto $
+1), начинается формирование импульса 9-го такта.
Задержка на 2 м.ц. нужна для соблюдения условия: интервал времени формирования
нулевого уровня на линии SCL должен быть больше или равен 5 мкс.
А вот далее, в ходе работы над программой, "мой лоб уперся в стену".
Ранее я предполагал, что формирование импульса АСК заканчивается в момент начала
формирования бита №7 следующего байта.
Но как, в этом случае, "помощник узнает" о моменте начала формирования бита №7
следующего байта, ведь, при формировании импульса АСК, вывод SDA "помощника"
работает "на выход"?
Вывод: по линии SDA, такую "комбинацию из двух пальцев провернуть" нельзя, так
как, кроме того, что нулевой уровень АСК "заторчит" на линии SDA "навечно" (не
закончится), будет еще и электрический конфликт (объединение выходов).
Далее, с фатальной неизбежностью, мой "яростный" взор тупо и "кровожадно"
упирается в импульс 9-го такта (а упираться-то больше и не в чего).
Один импульс это 2 строба, и какой-то из них должен "положить конец" формированию
импульса АСК (другого не дано).
Передний строб (переход от 0 к 1) отпадает, так как окончание еще не начавшегося
импульса есть абсурд.
Остается задний строб (переход от 1 к 0).
А вот с ним уже "кашу сваришь", так как сформировать его можно после того, как
нулевой уровень сигнала АСК достаточное время (необходимое для его обнаружения
"мастером") "поторчит" на линии SDA.
"Зер гут"!!!
После этого следует достаточно немудреный "мозговой штурм" (с учетом предыдущего
"въезда"), результат которого Вы видите на рис. 2Б (в части касающейся 9-го такта).
Итак, сначала формируется строб 9-го такта (bsf PortB,SCL).
Потом, как и было оговорено ранее, "мастер" перестраивает свой вывод SDA с работы
"на выход" на работу "на вход" (готовится к приему сигнала АСК).
Моментом окончания этой перестройки будет конец машинного цикла, в течение
которого исполняется команда bsf TrisB,SDA.
После этого, в части касающейся линии SDA, и "мастер", и "помощник" будут работать
"на вход".
А раз это так, то на линии SDA, через внутренний подтягивающий резистор вывода
RB7, будет выставлена 1 (пассивное состояние).
Таким образом, на линии SDA "родился" строб (переход от 0 к 1), который и является
сигналом к началу формирования импульса АСК.
Через некоторое, достаточно короткое (короткий импульс на линии SDA) время,
необходимое для принятия "помощником" решения о выдаче (или нет) в линию SDA
нулевого уровня сигнала АСК (в случае успешной обработки принятого им байта), на
линии SDA формируется спад импульса АСК (переход от 1 к 0).
После этого, при помощи команды btfsc PortB,SDA, являющейся одной из команд ПП
"плавающей" задержки АСК, "мастер" осуществляет проверку состояния линии SDA.
В случае обнаружения им нуля, "ухода" в "плавающую" задержку не происходит, что
соответствует исполнению "виртуального NOPа".
Итак, "миссия выполнена" и можно завершить формирование импульса 9-го такта, что и
имеет место быть (bcf PortB,SCL).
В свою очередь, по спаду (заднему стробу) импульса 9-го такта, завершается

15
формирование сигнала АСК.
Проверяю длительность импульса 9-го такта: она больше 4 мкс., то есть, 5 мкс. и
никогда не будет меньше 5 мкс., так как "из песни слов не выкинешь" ("выкидывать"
нечего).
Короче, норма.
Далее, "мастер" должен перестроиться с работы "на вход" на работу "на выход", что и
имеет место быть.
На время исполнения первых 2-х команд этой перестройки, на линии SDA
выставляется 1 (пассивное состояние).
Что "выставится" на линии SDA после окончания этого пассивного состояния?
А то, что "лежит" в защелке вывода RB7.
В данном случае, в ней хранится 0 (значение бита №0 режимного байта равно 0), значит
0 и "выставится" (см. рис. 2Б).
Если будет храниться 1 (в других случаях), значит "выставится" 1.
Все, режимный байт обработан и можно переходить (return) к аналогичной обработке
старшего байта адреса (через "администраторскую" ПП).
Затем та же участь ожидает младший байт адреса и байт данных. Повторяться не буду.

Далее, формируется стоп-условие.


Для начала, нужно выставить на линии SDA ноль, ведь на входе в группу команд
формирования стоп-условия, на линии SDA может быть как 0, так и 1 (зависит от
состояния бита №0 байта данных).
Выставил (bcf PortB,SDA).
Далее, "перестраховочная" задержка (nop).
Далее, выполняю требования по формированию стоп-условия:
- формирую единичный уровень на линии SCL (bsf PortB,SCL),
- формирую фиксированную задержку (goto $+1 и nop),
- формирую единичный уровень на линии SDA (bsf PortB,SDA).
Итак, строб стопа на линии SDA сформирован, и теперь нужно "зажечь" светодиод
окончания записи.
"Зажег" (bsf PortB,1).
Можно "уходить в мертвое, вечное кольцо", но "уходить" в него нужно с умом, не
забывая про WDT, иначе программа будет периодически стартовать (многократно
исполняться), а нужен только один полный цикл программы.
А посему, "врезаю" команду clrwdt в полный цикл ПП (без названия) "мертвого, вечного
кольца".
Все.

"Расширяю и углубляю" далее.


Ранее я говорил, что, в начале обработки текущего байта, существуют "эпюрные"
различия, обусловленные состоянием бита №0 предшествующего байта.
То же самое можно сказать и в части касающейся начала формирования стоп-условия.
Все познается в сравнении.
А раз это так, то вот Вам картинка:

16
Ранее я внес коррективы в принцип формирования сигнала АСК, следовательно, с целью
"привязки" этой картинки к работе программы Write_1.asm, нужно внести коррективы
в рис. 5 подраздела 1/2 (в части касающейся формирования сигнала АСК). Получилось
вот что:

17
Обратите внимание: то, что ранее называлось "кратковременным конфликтом", "кануло в
небытие". При такой конструкции программы, его просто нет.
Аналогичную картинку, в части касающейся записи, отредактирую в следующем
подразделе. Теперь "вскакивает" следующий вопрос: "А нельзя ли сделать программу
более быстрой и меньшего объема"?
Ответ: можно и нужно, так как используется достаточно современная м/схема памяти,
скорость работы которой выше "планки", заданной предельными временными
параметрами концепции I2C.

Адаптация программы Write_1.asm под предельные временные параметры


м/схемы 24С64А.
Для начала, нужно с ними определиться. Цифры, которые Вы видите на этой картинке, взяты
из технической документации м/схемы 24С64А.

Эта "цифирь" внушает сильнейший оптимизм, который, на практике, выражается в том, что из
программы Write_1.asm просто-напросто убираются все фиксированные задержки (то,
что на рис. 2 выделено желтым цветом), а это худо - бедно, но 8 команд, плюс,
существенный выигрыш в скорости, который гораздо больше суммарного времени
исполнения этих команд, так как имеет место быть многоцикловая ПП BAIT_WR.

18
У кого есть желание, можете просчитать этот выигрыш.
"Скомпрессированная" таким образом программа называется Write_2.asm.
Вот уж в ней, точно нет ничего лишнего. Программа проверена в работе. Работает четко.
;********************************************************************************
; Write_2.asm ЗАПИСЬ В 24С64А ОДНОГО БАЙТА ДАННЫХ (учебная, одноцикловая
; программа). Анализ состояний флага АСК осуществляется в ПП
; "плавающей" задержки.
; Эта программа адаптирована под предельные временные параметры 24С64А и
; является более высокоскоростной, чем программа Write_1.asm)
;********************************************************************************
; "Практикум по конструированию устройств на PIC контроллерах".
; Автор: Корабельников Евгений Александрович
; http://ikarab.narod.ru karabea@lipetsk.ru
;********************************************************************************
; "Мастер" - PIC16F84A. "Помощник" - 24C64A.
; Кнопка пуска записи подключена к выводу RB0.
; Светодиод (индицирует конец цикла записи) подключен к выводу RB1.
; Вывод RB6 подключен к линии такта (SCL).
; Вывод RB7 подключен к линии данных (SDA).
; Кварц 4 Мгц. (1м.ц.=1мкс.). Объем программы: 52 команды.
;********************************************************************************
LIST p=16F84A ; Установка типа микроконтроллера.
__CONFIG 03FF5H ; Бит защиты выключен, WDT включен,
; стандартный XT - генератор.
;================================================================================
; Определение положения регистров специального назначения.
;================================================================================
OptionR equ 01h ; Регистр OptionR - 1-й банк.
Status equ 03h ; Регистр выбора банка.
TrisB equ 06h ; Регистр TrisB - 1-й банк.
PortB equ 06h ; Регистр управления защелками порта В.
;================================================================================
; Определение названий и положения регистров общего назначения.
;================================================================================
Temp equ 0Ch ; Регистр, в котором происходит сдвиг.
Count equ 0Dh ; Счетчик битов байта.
;================================================================================
; "Привязка" названий битов регистров специального назначения к номерам битов.
;================================================================================
RP0 equ 5 ; Бит выбора банка.
C equ 0 ; Бит флага переноса-заёма.
SCL equ 6 ; Бит регистра PortB, который формирует такт.
SDA equ 7 ; Бит регистра PortB, который формирует данные
;================================================================================
; Определение места размещения результатов операций.
;================================================================================
F equ 1 ; Результат направить в регистр.
W equ 0 ; Результат направить в аккумулятор.
;================================================================================
org 0 ; Начать выполнение программы с PC=0.

19
;********************************************************************************
; "РАБОЧАЯ ЧАСТЬ" ПРОГРАММЫ.
;********************************************************************************
; Подготовительные операции.
;================================================================================
bsf Status,RP0 ; Переход в 1-й банк.
movlw b'00000001' ; RB0 (к нему подключена кнопка) работает "на
movwf TrisB ; вход", остальные RB... работают на выход.
movlw b'01111101' ; Предделитель с Кдел.=32 подключен к выходу
movwf OptionR ; WDT,подтягивающие резисторы порта В включены
bcf Status,RP0 ; Переход в 0-й банк.
movlw b'11000000' ; На линиях SDA и SCL выставляются единицы,
movwf PortB ; светодиод погашен.
;---------------------------------------------------------
; Ожидание нажатия кнопки.
;---------------------------------------------------------
KNOPKA_NO clrwdt ; Сброс WDT.
btfsc PortB,0 ; Если кнопка отжата, то уход в
goto KNOPKA_NO ; "вечное кольцо" ПП KNOPKA_NO.
; Если нажата, то программа исполняется далее.
;********************************************************************************
; ПРОЦЕДУРА ЗАПИСИ
;********************************************************************************
; Формирование старт-условия.
;================================================================================
bcf PortB,SDA ; SDA=0.
bcf PortB,SCL ; SCL=0.
;================================================================================
; "Администраторская" ПП (без названия), "рулящая" очередностью обработки байтов.
;================================================================================
; Задание числового значения режимного байта.
;---------------------------------------------------
movlw B'10100000' ; Запись в регистр Temp режимного байта (1010-
movwf Temp ; код функциональности, 000–адрес м/схемы,
; 0–режим записи).
call BAIT_WR ; Условный переход в ПП BAIT_WR.
;-----> Возврат по стеку из ПП BAIT_WR.
;---------------------------------------------------
; Задание числового значения старшего байта адреса.
;---------------------------------------------------
movlw .0 ; Запись в регистр Temp
movwf Temp ; старшего байта адреса.
call BAIT_WR ; Условный переход в ПП BAIT_WR.
;-----> Возврат по стеку из ПП BAIT_WR.
;---------------------------------------------------
; Задание числового значения младшего байта адреса.
;---------------------------------------------------
movlw .2 ; Запись в регистр Temp
movwf Temp ; младшего байта адреса.
call BAIT_WR ; Условный переход в ПП BAIT_WR.
;-----> Возврат по стеку из ПП BAIT_WR.
;---------------------------------------------------
; Задание числового значения байта данных.
;---------------------------------------------------

20
movlw .47 ; Запись в регистр Temp байта данных,
movwf Temp ; предназначенного для записи (2Fh).
call BAIT_WR ; Условный переход в ПП BAIT_WR.
;-----> Возврат по стеку из ПП BAIT_WR.
;================================================================================
; Формирование стоп-условия.
;================================================================================
bcf PortB,SDA ; SDA=0.
bsf PortB,SCL ; SCL=1.
bsf PortB,SDA ; SDA=1.
;================================================================================
; Завершение полного цикла программы.
;================================================================================
bsf PortB,1 ; Светодиод "загорелся".
clrwdt ; Сброс WDT.
goto $-1 ; Уход в "мертвое", "вечное кольцо".
;********************************************************************************
; Подпрограмма обработки байта.
;********************************************************************************
BAIT_WR movlw .8 ; Запись в счетчик битов количества
movwf Count ; битов в одном байте.
;================================================================================
; Обработка текущего бита
;================================================================================
SNOVA rlf Temp,F ; Циклический сдвиг влево. Этим обеспечивается
; обработка битов байта, начиная с бита №7.
bcf PortB,SDA ; SDA=0.
btfsc Status,C ; Что "ушло" в бит С?
bsf PortB,SDA ; Если в бите С 1, то SDA=1.
bsf PortB,SCL ; SCL=1.
bcf PortB,SCL ; SCL=0.
decfsz Count,F ; Декремент счетчика битов (Count-1=...).
goto SNOVA ; Если результат не=0, то переход на обработку
; следующего бита.
;********************************************************************************
; Группа команд формирования импульса 9-го такта и анализа состояний флага АСК.
;********************************************************************************
; Начало формирования импульса 9-го такта.
;--------------------------------------------------------------------------------
bsf PortB,SCL ; Формируется строб (перепад от 0 к 1)
; импульса 9-го такта.
;--------------------------------------------------------------------------------
; Подготовка к анализу состояний флага АСК (перестройка направления работы RB7).
;--------------------------------------------------------------------------------
bsf Status,RP0 ; Переход в 1-й банк.
bsf TrisB,SDA ; Вывод SDA работает на вход.
bcf Status,RP0 ; Переход в 0-й банк.
;================================================================================
; Анализ состояний флага АСК ("плавающая" задержка).
;================================================================================
ACK btfsc PortB,SDA ; На линии SDA 0 или 1 ?
goto ACK ; Если 1, то снова анализ.
;--------------------------------------------------------------------------------
; Конец формирования импульса 9-го такта.
;--------------------------------------------------------------------------------

21
bcf PortB,SCL ; Если 0, то формируется спад 9-го импульса
;--------------------------------------------------------------------------------
; Обратная перестройка направления работы вывода RB7.
;--------------------------------------------------------------------------------
bsf Status,RP0 ; Переход в 1-й банк.
bcf TrisB,SDA ; Вывод SDA работает на выход.
bcf Status,RP0 ; Переход в 0-й банк.
return ; Возврат по стеку в "администраторскую" ПП.
;********************************************************************************
end ; Конец программы.

22
А вот Вам и "скомпрессированные" (относительно рисунка 2) эпюры:

Эта картинка даже проще для понимания, чем рис. 2.


Собственно говоря, никаких дополнительных пояснений она не требует ("толковище" -
см. выше) и все на ней как на ладони.
Обращаю Ваше внимание на то, что программу Write_2.asm я "сваял" под конкретную
м/схему памяти.

23
Если речь идет о других типах м/схем памяти, то нужно "примериться" к их
предельным, временным параметрам (и если нужно, то внести коррективы).
В этом смысле, программа Write_1.asm является более универсальной, так как ее
задержки обеспечивают работу практически с любым типом м/схем памяти
(аналогичным 24С64А).
Как там чувствует себя наш амнезийный боец?
Один раз ложку ко рту подносить научился. Ноги уже не протянет.
Теперь, для того чтобы он как следует "наелся", нужно научить его, как "выхлебать всю
миску", а то ведь жалко бедолагу - кожа да кости. Да и какой из него работник? Ветром
качает (одной ложкой сыт не будешь).
Вот этим благородным и боготворительным ("откормочным") делом я и займусь в
следующем подразделе.

24
25