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

2/2.

Запись массива байтов в пределах одной страницы,нескольких


страниц, нескольких блоков. Ответы на "фурункулезные"
вопросы. Общий итог по записи.

В предыдущем подразделе, имела место быть "материнская" программа, которую нужно, по


принципу "от простого к сложному", "трансформировать" в нечто более "солидное", то
есть, в программу записи массива байтов данных, в пределах страницы памяти (для
начала).
Но вопрос-то с объемом страницы памяти остается пока открытым (32 или 256 байтов?)!
Следовательно, при составлении программы, нужно ориентироваться на меньший
объем в 32 байта, а когда все это "хозяйство" нормально заработает, можно будет, при
помощи "лома" практики, получить совершенно однозначный ответ на этот вопрос.
Собственно говоря, и сделать-то нужно самую малость - "поставить на счетчик" "поток"
байтов, определив тем самым количество записываемых байтов.
После записи последнего байта - "стоп-машина" с уходом в "мертвое, вечное кольцо".
Принципиальная схема проверочного устройства - без изменений.
Проверка записи - в том же PonyProg.
С адресами все понятно: при потоковой записи, в пределах страницы памяти, они будут
инкрементироваться от заданного, в адресном запросе, адреса.
При выборе адреса, который должен быть указан в адресном запросе, удобнее всего
"привязаться" к адресу 00h, так как это адрес 1-й ячейки памяти 1-й страницы.
Байты с какими числовыми значениями, и в каком порядке, записывать в ячейки?
Тут "намудрить" можно много всякого, например, записать осмысленный текст, но, на
первых порах, это противопоказано.
Нужно что-нибудь попроще (с меньшим количеством команд), и чтобы в ячейки памяти
записывалось не одно и то же число, а разные числа.
Наиболее просто это реализуется при помощи группы команд, организующей (на
каждом "витке" записи текущего байта данных, а именно, в его конце) инкремент
числового значения текущего байта данных.
Если, за начальную точку отсчета принять 0 (записать байт 00h по адресу 00h), то, в данном
случае, в первые 32 ячейки памяти запишутся числа, в точности повторяющие числовые
значения адресов ячеек.
При этом не следует путать числовое значение адреса и числовое значение байта,
записанного по этому адресу.
Просто, в данном случае, они будут равны.
Это равенство обусловлено тем, что 2 функционально обособленных инкремента
(программный инкремент значения байта данных и автоинкремент счетчика адреса)
происходят от одной и той же точки отсчета (от нуля).
Обращаю Ваше внимание на то, что, в данном случае, это равенство имеет место быть
только в пределах 1-й страницы памяти, а в пределах остальных страниц, оно
соблюдаться не будет (начальная точка отсчета адреса будет отлична от 0).

1
Получилась вот такая программа, с названием Write_3.asm:

;********************************************************************************
;
; Write_3.asm ЗАПИСЬ В 24С64А МАССИВА БАЙТОВ (учебная программа).
; Потоковая запись байтов данных в одну страницу памяти.
;
;********************************************************************************
; "Практикум по конструированию устройств на PIC контроллерах".
; Автор: Корабельников Евгений Александрович
; http://ikarab.narod.ru karabea@lipetsk.ru
; Эта программа входит в состав 2-го подраздела 2-го раздела.
;********************************************************************************
; "Мастер" - PIC16F84A.
; "Помощник" - 24C64A.
; Кнопка пуска записи подключена к выводу RB0.
; Светодиод (индицирует конец цикла записи массива байтов) подключен к
; выводу RB1.
; Вывод RB6 подключен к линии такта (SCL).
; Вывод RB7 подключен к линии данных (SDA).
; Кварц 4 Мгц. (1м.ц.=1мкс.).
; Объем программы: 59 команд.
;********************************************************************************
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 ; Счетчик битов байта.
Inc_Data equ 0Eh ; Регистр хранения текущего байта данных.
;================================================================================
; "Привязка" названий битов регистров специального назначения к номерам битов.
;================================================================================
RP0 equ 5 ; Бит выбора банка.
C equ 0 ; Бит флага переноса-заёма.
Z equ 2 ; Бит нулевого результата.
SCL equ 6 ; Бит регистра PortB, который формирует такт.
SDA equ 7 ; Бит регистра PortB, который формирует данные.

;================================================================================
; Определение места размещения результатов операций.
;================================================================================
F equ 1 ; Результат направить в регистр.

2
W equ 0 ; Результат направить в аккумулятор.
;================================================================================
org 0 ; Начать выполнение программы с нулевого адреса PC.

;********************************************************************************

;********************************************************************************
; "РАБОЧАЯ ЧАСТЬ" ПРОГРАММЫ.
;********************************************************************************
; Подготовительные операции.
;================================================================================
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 .0 ; Значение байта данных, записываемого в ячеку
movwf Inc_Data ; памяти с самым младшим (в пределах страницы)
; адресом.

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

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

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

;---------------------------------------------------
; Задание числового значения байта данных.
;---------------------------------------------------
POVTOR movf Inc_Data,W ; Копирование содержимого текущего байта
movwf Temp ; данных из регистра Inc_Data в регистр Temp.
call BAIT_WR ; Условный переход в ПП обработки байта BAIT_WR.
;-----> Возврат по стеку из ПП BAIT_WR.

;--------------------------------------------------------------------------------
; Приращение содержимого байта данных (+1) перед его записью в следующую
; ячейку памяти.
;--------------------------------------------------------------------------------
incf Inc_Data,F ; Inc_Data + 1 = ...
movlw .32 ; Число .32, в данном случае, одновременно
; задает и количество записываемых байтов, и
; их числовые значения.
subwf Inc_Data,W ; Inc_Data - W = ... Результат - в W.
btfss Status,Z ; Результат вычитания равен или нет нулю?
goto POVTOR ; Нет, не равен - текущий байт данных записывается.
; Да, равен - формирование стоп-условия.

;================================================================================
; Формирование стоп-условия.
;================================================================================
bcf PortB,SDA ; SDA=0.
bsf PortB,SCL ; SCL=1.
bsf PortB,SDA ; SDA=1.

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

;********************************************************************************
; Подпрограмма обработки байта.

4
;********************************************************************************
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.
bsf PortB,SCL ; SCL=1. (Если в бите С 0, то предыдущая
; команда не исполняется. Вместо нее –
; "виртуальный" NOP).
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, то снова анализ (задержка до
; появления 0).

;--------------------------------------------------------------------------------
; Конец формирования импульса 9-го такта.
;--------------------------------------------------------------------------------
bcf PortB,SCL ; Если 0, то формируется спад импульса 9-го такта.

5
;--------------------------------------------------------------------------------
; Обратная перестройка направления работы вывода RB7.
;--------------------------------------------------------------------------------
bsf Status,RP0 ; Переход в 1-й банк.
bcf TrisB,SDA ; Вывод SDA работает на выход.
bcf Status,RP0 ; Переход в 0-й банк.

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

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

Эту программу я "сваял" на основе "быстрой" программы Write_2.asm, работа которой


"расписана" в предыдущем подразделе.
А раз это так, то объясню только специфику программы Write_3.asm.
Организован регистр Inc_Data, содержимое которого и записывается в текущую ячейку
памяти.
В начале процедуры записи, в нем выставляется ноль (movlw .0 и movwf Inc_Data).
После записи его содержимого в текущую ячейку памяти (записи текущего байта), оно
(содержимое) инкрементируется (incf Inc_Data,F), и, на следующем "витке"
внутреннего цикла потоковой записи, в следующую ячейку, будет записан байт данных
с числовым значением на 1 большим, чем числовое значение предыдущего, записанного
байта данных.
После команды incf Inc_Data,F, следуют команды movlw .32 и subwf Inc_Data,W, то
есть, из содержимого регистра хранения текущего байта данных Inc_Data вычитается
число .32.
Это число задает количество ячеек памяти, в которые, в пределах страницы,
производится запись.
Далее анализируется состояние флага Z.
Если результат вычитания не=0, то осуществляется переход на метку POVTOR (goto
POVTOR) и, по автоинкрементированному адресу (в следующую ячейку памяти),
начинается запись следующего байта данных с числовым значением на 1 большим, чем
числовое значение ранее записанного байта.
После того, как результат вычитания станет =0 (после записи 32-го байта данных в
ячейку памяти с адресом 1Fh) - "стоп-машина" и уход в "мертвое, вечное кольцо".
Вот и вся премудрость.
После считывания данных из 24С64А в PonyProg, в первых двух строках окна
программы, Вы увидите:
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F

Это означает, что в первые 32 ячейки памяти 24С64А последовательно (потоково) записались
байты данных с требуемыми (в данном случае) значениями.
Примечание: если нужно будет произвести повторную запись (например, после
изменения константы и т.п.), то, перед записью, запишите в 24С64А (в ПониПроге),
например, тот же HEX файл программы Write_3.asm, то есть, "забейте" ячейки какой-
нибудь "цифирью", чтобы, при дальнейшем считывании в ПониПроге, наглядно был
виден результат записи, произведенной в проверочном устройстве.
При помощи редактирования буфера, "забивать" эти ячейки "цифирью" трудоемко и

6
долго, а указанным выше способом - в самый раз.
Итак, пришло время ответить на сформулированный ранее "фурункулезный" вопрос:
"32 страницы по 256 байтов или 256 страниц по 32 байта"?
Для этого, всего-то и нужно, увеличить значение константы .32, "отвечающей" за
количество байтов в массиве.
Сделайте ее, например, .40 и посмотрите что будет.
А будет выход на 2-е "кольцо" записи (в пределах страницы) и последние 8 байтов с
числовыми значениями от 20h до 27h будут записаны в первые 8 ячеек 1-й страницы
памяти "по верху" записанных в них ранее (на 1-м "кольце" записи) байтов с числовыми
значениями 00h ... 07h.
Чтобы убедиться в том, что есть и 3-е, и 4-е, и т.д. "кольца" записи, еще увеличьте это
число.
Вывод: м/схема памяти 24С64А имеет 256 страниц по 32 байта в каждой.
Патрик Гёлль оказался не прав.
Информация документации на 24С64А, в части касающейся способа страничной
организации памяти, соответствует действительности.
А вот теперь-то имеет место быть полная ясность в этом вопросе.
Лучше один раз увидеть, чем сто раз прочитать.
Напрасно ли проделана работа?
Не в коем разе. Именно такими, на первый взгляд, "нерациональными" способами,
постепенно и приобретается настоящий, высококлассный, практический опыт и
истинная (полностью осмысленная, в том числе и на подсознательном уровне)
уверенность в своих силах, что, согласитесь со мной, немаловажно.
Итак, после сделанного выше вывода, "вскакивает" очередной вопрос: "А если работать
только в пределах младшего байта адреса?
Сколько страниц он обслуживает"?
Теперь ответить на этот вопрос проще простого: 256:32=8 страниц.
Я это называю "блоком" (моя фантазия).
В понятийном смысле, это очень удобно, так как младший байт адреса обслуживает
один блок, а количество этих блоков задается старшим байтом адреса.
Итак, блок содержит в себе 256 байтов, следовательно, объем памяти 24С64А состоит из
32-х блоков (32х256=8192 байта).
К чему я это говорю?
А не проще ли обойтись без понятия "блок", а использовать стандартную терминологию "256
страниц по 32 байта", ведь "что в лоб, что по лбу, все едино"?
Во-первых, лично у меня, с целью наведения порядка в своем "мозговом хозяйстве",
душа лежит к тому, чтобы к младшему байту адреса было "привязано" привычное число
256 (а не 32), а старший байт адреса определял бы количество "нарезанных" таким
образом "кусков", а во-вторых, мыслить так гораздо удобнее, и особенно в случае записи
массива байтов, состоящего из нескольких блоков.
Очень часто, на практике, происходит именно такая запись (если использовать объем
памяти "по-мизеру", то "за что кровь проливали"?), и в этом случае, удобнее оперировать
блоками.
Если массив байтов имеет объем менее одного блока, то удобнее оперировать
страницами.
Соответственно, в своем "наборе инструментов", нужно иметь и ПП записи страниц в
пределах одного блока, и ПП записи блоков.
И еще, 32 блока означает, что в старшем байте адреса имеется 5 активных битов (2 в
степени 5 = 32) с №№0,1,2,3,4.
Биты с №№5,6,7 не активны (пассивны) и в них всегда нужно выставлять нули. Они

7
задействуются при объемах памяти более 8 Кбайт.
Программа Write_3.asm представляет собой программу потоковой записи, в пределах
одной страницы памяти.
О том, что с ней можно "поэкспериментировать", изменяя количество байтов данных в
записываемом блоке, говорилось выше.
Можно ли "поэкспериментировать" с числовым значением адресного запроса?
Да ради Бога, только учтите "кольцевую природу" страницы.
Далее, в развитие темы, нужно "сваять" программу, обеспечивающую
последовательную, потоковую запись байтов данных в несколько страниц памяти,
вплоть до заполнения данными одного блока памяти (8-ми страниц памяти).
Сразу "вскакивает" вопрос о "привязке" конкретных страниц к конкретным адресам
ячеек памяти.
А все очень просто: вся память "нарезана" на "куски" (страницы) объемом в 32 байта, и за
последней ячейкой памяти предыдущей страницы следует первая ячейка памяти
следующей страницы.
Чтобы проще было ориентироваться, я все это "хозяйство" разрисовал.
Получилось вот что.

8
9
Программа Write_3.asm, по умолчанию, работает в адресных границах 1-й страницы, но,
изменив "начальную точку отсчета", можно записать байты данных в любую из 256-ти
страниц.
Пошли дальше.
Теперь, с целью создания программы, осуществляющей блочную запись (запись
нескольких страниц, в пределах одного блока, вплоть до полного его заполнения)
нужно соответствующим образом "модернизировать" программу Write_3.asm.
Эта программа называется Write_4.asm.
В ней нужно, после заполнения данными текущей страницы, перейти на заполнение
данными страницы со следующим (+1) номером (все эти "дела лелаются" в границах
блока).
А раз это так, то нужно этот процесс "поставить на счетчик", который задает количество
обрабатываемых страниц, равное 8-ми.
Создаю под этот счетчик регистр общего назначения с названием CountPage и в
подготовительных операциях ПП START, записываю в него число .8.
В данном случае, после формирования стоп-условия, в "мертвое, вечное кольцо"
уходить не нужно, а нужно "врезать" в текст программы (после стоп-условия) группу
команд, обеспечивающих "скачкообразное" (+.32) приращение адреса (для обеспечения
перехода на начало следующей страницы) и декремент содержимого регистра
CountPage (decfsz), с целью либо перехода на начало записи следующей страницы
(сценарий №1), либо ухода в "мертвое, вечное кольцо" (сценарий №2).
Что из себя должна представлять эта группа команд?
В соответствии с ранее сделанными предположениями, после записи последнего байта в
страницу памяти, должно быть сформировано стоп-условие (это есть).
Затем, должен иметь место быть ждущий режим (не менее 5 мкс.), в течение которого
должно произойти "скачкообразное" приращение содержимого (+.32) регистра
младшего разряда адреса (адресная подготовка к обработке следующей страницы).
Затем, для последующей идентификации номера текущей страницы памяти, должен
быть осуществлен декремент содержимого регистра счетчика номера страницы
CountPage с ветвлением (decfsz).
Кульминация - ответ на вопрос: "Переходить на запись массива байтов в следующую
страницу памяти или завершить запись"?
При таком "раскладе", длительность нахождения в ждущем режиме (не менее 5 мкс.)
обеспечивается без задействования дополнительных команд фиксированной задержки
(за счет уже имеющихся команд).
В соответствии с этой "концепцией", и "ваяю" программу Write_4.asm.
В проверочном устройстве, произвожу запись блока и, радостно потирая руки,
считываю в ПониПроге результат записи.
Сокрушительный облом!!!
Записывается только 1-я страница, и не более того.
К тому же, замысел настолько прост и группа команд, речь о которой шла выше,
настолько незамысловата, что ошибиться в ее составлении просто невозможно.
Вывод: ошибка в стратегии, и менно на "участке" ждущего режима. Другого не дано.
"Участок" ждущего режима представляет собой банальные единицы на линии SCL и
SDA, выставленные "мастером" между стоп и старт-условиями.
А посему, единственный значащий памаметр этого "участка" - его протяженность во
времени, и именно в этом "корень зла".
Единственное предположение, которое, в связи с этим приходит в голову, это
предположение о том, что "маловата будет кольчужка" и время нахождения в ждущем
режиме нужно увеличивать.

10
Вопрос: "С чем это может быть связано"?
Ответ: с чем-то, что связано с процедурой окончания потоковой записи в страницу.
Отсюда возникает предположение, что, в конце блочной записи в страницу, не
зависимо от объема записываемого в него массива байтов, в 24С64А, исполняется некая
процедура, которая требует для своего завершения "приличного" времени, и пока эта
процедура полностью не будет отработана, 24С64А просто-напросто не реагирует на
управляющие сигналы "мастера".
Что это за "некая процедура"?
Ответ однозначен. Это процедура записи в страницу всего массива байтов, а не
отдельных байтов этого массива.
Что-то, где-то такое, подобное было ...
Вызываю "летающую корову" по имени "запись в EEPROM память ПИКа массива
байтов".
Ага, в этом случае, задержка нужна для гарантированного завершения процедуры
записи каждого байта в одну из ячеек памяти (под каждый байт - своя задержка).
Сразу возникает 2 вопроса:
1. У нас-то речь идет не о записи одного байта, а о записи массива байтов (в
рассматриваемом случае, из 32-х байтов), и соответственно, не о массиве задержек
(нескольких задержках), а об одной задержке (под весь массив)?
2. Как быть с "плавающей" задержкой, ведь, в ждущем режиме, сигнала АСК нет?
Ответ на 1-й вопрос.
Единственно разумным будет предположить, что регистр данных 24С64А является не
однобайтным, а 32-байтным, и запись байтов данных в ячейки памяти, при работе в
"границах" одной страницы памяти, происходит не многократно и последовательно (во
время формирования сигналов АСК), а единожды.
Это означает то, что, в пределах одной страницы, по ходу формирования "помощником"
сигналов АСК под каждый байт данных, происходит последовательное заполнение,
предназначенными для записи байтами, 32-байтного регистра данных 24С64А.
В данном случае, регистр данных выполняет функцию 32-байтной оперативной,
буферной памяти, функция которой - накопление данных для того чтобы, в конце
вывода на запись всего массива байтов (в пределах страницы), единожды ("оптом") его
записать.
Из этого следует то, что сигналы АСК, формируемые "помощником" под каждый байт,
предназначенного для записи, массива байтов, прямого (непосредственного) отношения
к "рабочей" процедуре записи не имеют.
Они имеют к ней только косвенное отношение, выражающееся в подготовке к записи, и
не более того.
Так зачем тогда нужны эти сигналы АСК?
Ответ напрашивается сам по себе: сигналы АСК "регистрируют" только факт записи
текущего байта данных в 32-байтную оперативную память (то есть, в регистр данных,
сконфигурированный под процедуру записи) и его готовность к принятию в свои
"закрома" следующего байта данных, но не факт записи байта данных в ячейку
EEPROM памяти 24С64А.
Запись же всего массива данных страницы, в ячейки EEPROM памяти 24С64А,
происходит "оптом", сразу же после формирования стоп-условия, то есть, именно строб
стоп-условия, а не строб сигнала АСК (как это предполагалось ранее), включает
внутренний RC генератор 24С64А, импульсная последовательность которого и
принимает участие в процедуре "оптовой" записи.
А раз это так, то из этого следует вывод: в конце процедуры записи текущего
массива байтов в страницу памяти (сразу же после формирования стоп-условия), для

11
гарантированно надежного завершения процедуры записи всего этого массива
байтов и обеспечения успешной записи следующего массива байтов, "мастеру"
необходимо сформировать задержку величиной не менее "паспортного" цикла
записи.
Для 24С64А, она составляет не менее 5 мс. (5000 мкс.).
Реально же, можно сформировать задержку и меньшей величины (вплоть до 1 мс.,
проверено, "мин нет"), но я буду ориентироваться на 5 мс.
Причина указанного выше "облома" состоит в том, что это требование не было
выполнено, вследствие чего, "мастер" пытался безуспешно "достучаться" до помощника
в то время, когда "помощник", довольно-таки длительное время, занимался своими
"внутренними делами" и полностью "игнорировал приказы начальства" ("моя твоя не
понимайт").
Тогда возникает следующий вопрос: "В программе Write_3.asm никакой задержки на
5000 мкс. нет. Почему происходит нормальная запись массива байтов в страницу"?
Ответ: да, "явно выраженной" (в виде ПП задержки) задержки на 5000 мкс. нет, но есть
задержка гораздо большей величины - задержка "мертвого, вечного кольца", которая
гарантированно обеспечивает завершение процедуры записи массива байтов в страницу
памяти.
Ответ на 2-й вопрос.
Ответ: а никак. В ждущем режиме сигнала АСК (а также и какого-либо другого критерия
окончания записи) нет, следовательно, "плавающую" задержку сформировать нельзя.
А раз это так, то необходимо сформировать фиксированную задержку (критерий задает
программист) с указанной выше величиной.
Для проверки всех этих рассуждений, я "сваял" программу Write_4.asm.

;********************************************************************************
; Write_4.asm ЗАПИСЬ В 24С64А МАССИВА БАЙТОВ (учебная программа) для
; случая заполнения данными, в одном полном цикле программы, до 8
; (включительно) страниц.
;********************************************************************************
; "Практикум по конструированию устройств на PIC контроллерах".
; Автор: Корабельников Евгений Александрович
; http://ikarab.narod.ru karabea@lipetsk.ru
; Эта программа входит в состав 2-го подраздела 2-го раздела.
;********************************************************************************
; "Мастер" - PIC16F84A.
; "Помощник" - 24C64A.
; Кнопка пуска записи подключена к выводу RB0.
; Светодиод (индицирует конец цикла записи массива байтов) подключен к
; выводу RB1.
; Вывод RB6 подключен к линии такта (SCL).
; Вывод RB7 подключен к линии данных (SDA).
; Кварц 4 Мгц. (1м.ц.=1мкс.).
; Объем программы: 75 команд.
;********************************************************************************
LIST p=16F84A ; Установка типа микроконтроллера.
__CONFIG 03FF5H ; Бит защиты выключен, WDT включен,
; стандартный XT - генератор.
;================================================================================
; Определение положения регистров специального назначения.
;================================================================================
OptionR equ 01h ; Регистр OptionR - 1-й банк.

12
Status equ 03h ; Регистр выбора банка.
TrisB equ 06h ; Регистр TrisB - 1-й банк.
PortB equ 06h ; Регистр управления защелками порта В.
;================================================================================
; Определение названий и положения регистров общего назначения.
;================================================================================
Temp equ 0Ch ; Регистр, в котором происходит сдвиг.
Count equ 0Dh ; Счетчик битов байта.
Inc_Data equ 0Eh ; Регистр хранения текущего байта данных.
Adr_L equ 0Fh ; Регистр хранения младшего байта адреса.
CountPage equ 10h ; Счетчик страниц.
Sec_L equ 11h ; Младший байт счетчика задержки.
Sec_H equ 12h ; Старший байт счетчика задержки.
;================================================================================
; "Привязка" названий битов регистров специального назначения к номерам битов.
;================================================================================
RP0 equ 5 ; Бит выбора банка.
C equ 0 ; Бит флага переноса-заёма.
Z equ 2 ; Бит нулевого результата.
SCL equ 6 ; Бит регистра PortB, который формирует такт.
SDA equ 7 ; Бит регистра PortB, который формирует данные.
;================================================================================
; Определение места размещения результатов операций.
;================================================================================
F equ 1 ; Результат направить в регистр.
W equ 0 ; Результат направить в аккумулятор.
;================================================================================
org 0 ; Начать выполнение программы с нулевого адреса PC.
;********************************************************************************

;********************************************************************************
; "РАБОЧАЯ ЧАСТЬ" ПРОГРАММЫ.
;********************************************************************************
; Подготовительные операции.
;================================================================================
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 ; светодиод погашен.

movlw .8 ; Запись в счетчик страниц


movwf CountPage ; количества страниц.
clrf Adr_L ; Начальная установка в Adr_L нулевого адреса.
;---------------------------------------------------------
; Ожидание нажатия кнопки.
;---------------------------------------------------------
KNOPKA_NO clrwdt ; Сброс WDT.

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

;********************************************************************************
; ПРОЦЕДУРА ЗАПИСИ
;********************************************************************************
; Формирование старт-условия.
;================================================================================
PAGE_YES bcf PortB,SDA ; SDA=0.
bcf PortB,SCL ; SCL=0.
;================================================================================
; "Администраторская" ПП (без названия), "рулящая" очередностью обработки байтов.
;================================================================================
movlw .0 ; Значение байта данных, записываемого в ячеку
movwf Inc_Data ; памяти с самым младшим (в пределах страницы) адресом.
;---------------------------------------------------
; Задание числового значения режимного байта.
;---------------------------------------------------
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.
;---------------------------------------------------
; Задание числового значения младшего байта адреса.
;---------------------------------------------------
movf Adr_L,W ; Запись в регистр Temp
movwf Temp ; младшего байта адреса.
call BAIT_WR ; Условный переход в ПП обработки байта BAIT_WR.
;-----> Возврат по стеку из ПП BAIT_WR.
;---------------------------------------------------
; Задание числового значения байта данных.
;---------------------------------------------------
POVTOR movf Inc_Data,W ; Копирование содержимого текущего байта
movwf Temp ; данных из регистра Inc_Data в регистр Temp.
call BAIT_WR ; Условный переход в ПП обработки байта BAIT_WR.
;-----> Возврат по стеку из ПП BAIT_WR.
;--------------------------------------------------------------------------------
; Приращение содержимого байта данных (+1) перед его записью в следующую
; ячейку памяти.
;--------------------------------------------------------------------------------
incf Inc_Data,F ; Inc_Data + 1 = ...
movlw .32 ; Число .32, в данном случае, одновременно
; задает и количество записываемых байтов, и
; их числовые значения.
subwf Inc_Data,W ; Inc_Data - W = ... Результат - в W.

14
btfss Status,Z ; Результат вычитания равен или нет нулю?
goto POVTOR ; Нет, не равен - текущий байт данных записывается.
; Да, равен - формирование стоп-условия.

;================================================================================
; Формирование стоп-условия.
;================================================================================
bcf PortB,SDA ; SDA=0.
bsf PortB,SCL ; SCL=1.
bsf PortB,SDA ; SDA=1.
;================================================================================
; Задержка 5мс. для обеспечения записи страницы.
;================================================================================
clrwdt ; Сброс WDT.
movlw .125 ;
movwf Sec_L ; Запись констант
movlw .7 ; задержки.
movwf Sec_H ;

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


goto WR_2 ; вычитающий,
decfsz Sec_H,F ; 2-байтный
goto WR_2 ; счетчик.
;-------------------------------------------------
; Подготовка к записи байтов в следующую страницу.
;-------------------------------------------------
movlw .32 ; "Скачкообразное" приращение младшего байта
addwf Adr_L,F ; адреса на 32 (20h) позиции.

decfsz CountPage,F ; Уменьшение номера страницы (-1).


goto PAGE_YES ; Если результат не=0, то переход на запись
; байтов в следующую страницу.
; Если =0, то программа исполняется далее.
;================================================================================
; Завершение полного цикла программы.
;================================================================================
bsf PortB,1 ; Светодиод "загорелся".
clrwdt ; Сброс WDT.
goto $-1 ; Уход в "мертвое", "вечное кольцо" до
; выключения и последующего включения питания.
;********************************************************************************
; Подпрограмма обработки байта.
;********************************************************************************
BAIT_WR movlw .8 ; Запись в счетчик битов количества
movwf Count ; битов в одном байте.
;================================================================================
; Обработка текущего бита.
;================================================================================
SNOVA rlf Temp,F ; Циклический сдвиг влево. Этим обеспечивается
; обработка битов байта, начиная с бита
; старшего разряда (№7...№0).
bcf PortB,SDA ; SDA=0.

15
btfsc Status,C ; Что "ушло" в бит С?
bsf PortB,SDA ; Если в бите С 1, то SDA=1.
bsf PortB,SCL ; SCL=1. (Если в бите С 0, то предыдущая команда не
; исполняется. Вместо нее "виртуальный" NOP).
bcf PortB,SCL ; SCL=0.
decfsz Count,F ; Декремент счетчика битов (Count-1=...).
goto SNOVA ; Если результат не=0, то переход на обработку следующего бита.
;********************************************************************************
; Группа команд формирования импульса 9-го такта и анализа состояний флага АСК.
;********************************************************************************
; Начало формирования импульса 9-го такта.
;------------------------------------------
bsf PortB,SCL ; Формируется строб (перепад от 0 к 1) импульса 9-го такта.
;------------------------------------------
; Подготовка к анализу состояний флага АСК.
;------------------------------------------
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 ; Конец программы.

Собственно говоря, специфика работы этой программы (относительно Write_3.asm)


"расписана" выше. Повторяться не буду.
По умолчанию, программа Write_4.asm записывает байты данных в пределах одного
блока памяти (заполняет данными 8 страниц памяти).
Изменяя числовое значение константы адресного запроса, можно заполнить байтами
данных любой другой блок памяти.
Меняя константу .8, например, на константу 2, 5 и т.д., можно записать в блок памяти
не все 8 страниц, а 2, 5 и т.д. страниц соответственно.
Не возбраняется также и "поиграть с константами", "отвечающими" за запись в пределах
страницы (программа учебная и можно "изгаляться" над ней как угодно).
Можно также, постепенно уменьшая время фиксированной задержки (начните от 1000
мкс.), выяснить реальную величину цикла записи Вашей 24С64А.
Кстати, если у кого-то из Вас имеется 24С32А, то это то же самое, что и 24С64А, только
"мозгов" в 2 раза меньше.

16
Развиваю тему дальше.
Вашему вниманию предлагается учебная программа, позволяющая заполнить данными
все 32 блока памяти 24С64А.
Она "родилась" из программы Write_4.asm путем организации дополнительного
счетчика блоков и называется Write_5.asm.
Способом, описанным выше, "ставлю на счетчик" количество блоков (.32) и "дело в
шляпе".
После обработки последнего (32-го) байта данных 8-й страницы 32-го блока, "стоп-
машина" и уход в "мертвое, вечное кольцо".
Вот и вся премудрость.

;********************************************************************************
; Write_5.asm ЗАПИСЬ В 24С64А МАССИВА БАЙТОВ (учебная программа) для
; случая заполнения данными, в одном полном цикле программы,
; всего объема памяти.
;--------------------------------------------------------------------------------
; Изменяя значения констант, можно изменять объем заполнения памяти данными.
;********************************************************************************
; "Практикум по конструированию устройств на PIC контроллерах".
; Автор: Корабельников Евгений Александрович
; http://ikarab.narod.ru karabea@lipetsk.ru
; Эта программа входит в состав 2-го подраздела 2-го раздела.
;********************************************************************************
; "Мастер" - PIC16F84A.
; "Помощник" - 24C64A.
; Кнопка пуска записи подключена к выводу RB0.
; Светодиод (индицирует конец цикла записи массива байтов) подключен к
; выводу RB1.
; Вывод RB6 подключен к линии такта (SCL).
; Вывод RB7 подключен к линии данных (SDA).
; Кварц 4 Мгц. (1м.ц.=1мкс.).
; Объем программы: 84 команды.
;********************************************************************************
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 ; Счетчик битов байта.
Inc_Data equ 0Eh ; Регистр хранения текущего байта данных.
Adr_L equ 0Fh ; Регистр хранения младшего байта адреса.
Adr_H equ 10h ; Регистр хранения старшего байта адреса.
CountPagL equ 11h ; Счетчик страниц.
CountPagH equ 12h ; Счетчик блоков страниц (в блоке - 32х8=256
; байтов).

17
Sec_L equ 14h ; Младший байт счетчика задержки.
Sec_H equ 15h ; Старший байт счетчика задержки.
;================================================================================
; "Привязка" названий битов регистров специального назначения к номерам битов.
;================================================================================
RP0 equ 5 ; Бит выбора банка.
C equ 0 ; Бит флага переноса-заёма.
Z equ 2 ; Бит нулевого результата.
SCL equ 6 ; Бит регистра PortB, который формирует такт.
SDA equ 7 ; Бит регистра PortB, который формирует данные.

;================================================================================
; Определение места размещения результатов операций.
;================================================================================
F equ 1 ; Результат направить в регистр.
W equ 0 ; Результат направить в аккумулятор.
;================================================================================
org 0 ; Начать выполнение программы с нулевого адреса PC.
;********************************************************************************

;********************************************************************************
; "РАБОЧАЯ ЧАСТЬ" ПРОГРАММЫ.
;********************************************************************************
; Подготовительные операции.
;================================================================================
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 ; светодиод погашен.

movlw .8 ; Запись в счетчик страниц


movwf CountPagL ; количества страниц в блоке.

movlw .32 ; Запись в счетчик страниц количества блоков


movwf CountPagH ; (32 блока по 32х8=256 байтов, то есть, 8192 байта).

clrf Adr_L ; Начальная установка в Adr_L нулевого адреса.


clrf Adr_H ; Начальная установка в Adr_H нулевого адреса.
;---------------------------------------------------------
; Ожидание нажатия кнопки.
;---------------------------------------------------------
KNOPKA_NO clrwdt ; Сброс WDT.
btfsc PortB,0 ; Если кнопка отжата, то уход в
goto KNOPKA_NO ; "вечное кольцо" ПП KNOPKA_NO.
; Если кнопка нажата, то программа исполняется далее.
;********************************************************************************
; ПРОЦЕДУРА ЗАПИСИ
;********************************************************************************
; Формирование старт-условия.

18
;================================================================================
PAGE_YES bcf PortB,SDA ; SDA=0.
bcf PortB,SCL ; SCL=0.
;================================================================================
; "Администраторская" ПП (без названия), "рулящая" очередностью обработки байтов.
;================================================================================
movlw .0 ; Значение байта данных, записываемого в ячеку
movwf Inc_Data ; памяти с самым младшим (в пределах страницы); адресом.

;---------------------------------------------------
; Задание числового значения режимного байта.
;---------------------------------------------------
movlw B'10100000' ; Запись в регистр Temp режимного байта (1010-
movwf Temp ; код функциональности, 000–адрес м/схемы, 0–режим записи).
call BAIT_WR ; Условный переход в ПП обработки байта BAIT_WR.
;-----> Возврат по стеку из ПП BAIT_WR.
;---------------------------------------------------
; Задание числового значения старшего байта адреса.
;---------------------------------------------------
movf Adr_H,W ; Запись в регистр Temp
movwf Temp ; старшего байта адреса.
call BAIT_WR ; Условный переход в ПП обработки байта BAIT_WR.
;-----> Возврат по стеку из ПП BAIT_WR.
;---------------------------------------------------
; Задание числового значения младшего байта адреса.
;---------------------------------------------------
movf Adr_L,W ; Запись в регистр Temp
movwf Temp ; младшего байта адреса.
call BAIT_WR ; Условный переход в ПП обработки байта BAIT_WR.
;-----> Возврат по стеку из ПП BAIT_WR.
;---------------------------------------------------
; Задание числового значения байта данных.
;---------------------------------------------------
POVTOR movf Inc_Data,W ; Копирование содержимого текущего байта
movwf Temp ; данных из регистра Inc_Data в регистр Temp.
call BAIT_WR ; Условный переход в ПП обработки байта BAIT_WR.
;-----> Возврат по стеку из ПП BAIT_WR.
;--------------------------------------------------------------------------------
; Приращение содержимого байта данных (+1) перед его записью в следующую
; ячейку памяти.
;--------------------------------------------------------------------------------
incf Inc_Data,F ; Inc_Data + 1 = ...
movlw .32 ; Число .32, в данном случае, одновременно
; задает и количество записываемых байтов, и
; их числовые значения.
subwf Inc_Data,W ; Inc_Data - W = ... Результат - в W.
btfss Status,Z ; Результат вычитания равен или нет нулю?
goto POVTOR ; Нет, не равен - текущий байт данных записывается.
; Да, равен - формирование стоп-условия.
;================================================================================
; Формирование стоп-условия.
;================================================================================
bcf PortB,SDA ; SDA=0.

19
bsf PortB,SCL ; SCL=1.
bsf PortB,SDA ; SDA=1.
;================================================================================
; Задержка 5мс. для обеспечения записи страницы.
;================================================================================
clrwdt ; Сброс WDT.
movlw .125 ;
movwf Sec_L ; Запись констант
movlw .7 ; задержки.
movwf Sec_H ;

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


goto WR_2 ; вычитающий,
decfsz Sec_H,F ; 2-байтный
goto WR_2 ; счетчик.
;-------------------------------------------------
; Подготовка к записи байтов в следующую страницу.
;-------------------------------------------------
movlw .32 ; "Скачкообразное" приращение младшего байта
addwf Adr_L,F ; адреса на 32 (20h) позиции.

decfsz CountPagL,F ; Уменьшение номера страницы (-1).


goto PAGE_YES ; Если результат не=0, то переход на запись байтов в следующую
; страницу. Если =0, то программа исполняется далее.
;------------------------------------------------
; Подготовка к записи следующего блока.
;------------------------------------------------
clrf Adr_L ; Установка в Adr_L нулевого адреса.
movlw .8 ; Запись в счетчик страниц
movwf CountPagL ; количества страниц в блоке.
incf Adr_H,F ; Задание адреса 1-й ячейки следующего блока.

decfsz CountPagH,F ; Уменьшение номера блока (-1).


goto PAGE_YES ; Если результат не=0, то переход на запись байтов в следующий
; блок. Если =0, то программа исполняется далее.
;================================================================================
; Завершение полного цикла программы.
;================================================================================
bsf PortB,1 ; Светодиод "загорелся".
clrwdt ; Сброс WDT.
goto $-1 ; Уход в "мертвое", "вечное кольцо" до
; выключения и последующего включения питания.
;********************************************************************************
; Подпрограмма обработки байта.
;********************************************************************************
BAIT_WR movlw .8 ; Запись в счетчик битов количества
movwf Count ; битов в одном байте.
;================================================================================
; Обработка текущего бита.
;================================================================================
SNOVA rlf Temp,F ; Циклический сдвиг влево. Этим обеспечивается
; обработка битов байта, начиная с бита
; старшего разряда (№7...№0).
bcf PortB,SDA ; SDA=0.

20
btfsc Status,C ; Что "ушло" в бит С?
bsf PortB,SDA ; Если в бите С 1, то SDA=1.
bsf PortB,SCL ; SCL=1. (Если в бите С 0, то предыдущая
; команда не исполняется. Вместо нее – "виртуальный" NOP).
bcf PortB,SCL ; SCL=0.
decfsz Count,F ; Декремент счетчика битов (Count-1=...).
goto SNOVA ; Если результат не=0, то переход на обработку следующего бита.

;********************************************************************************
; Группа команд формирования импульса 9-го такта и анализа состояний флага АСК.
;********************************************************************************
; Начало формирования импульса 9-го такта.
;------------------------------------------
bsf PortB,SCL ; Формируется строб (перепад от 0 к 1) импульса 9-го такта.
;------------------------------------------
; Подготовка к анализу состояний флага АСК.
;------------------------------------------
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-го, 10-го,
17-го и т.д.
Примечание: при заполнении байтами всего массива памяти, между нажатием на
кнопку "Пуск записи" и моментом "загорания" светодиода, проходит некоторое время.
"На закуску" - ответ на последний "фурункулезный" вопрос о возможности или нет
записи от текущего адреса, в пределах страницы памяти.
Нет проблем.

21
Беру программу Write_3.asm (запись в пределах страницы памяти) и "моделирую" эту
ситуацию (во втором массиве данных отсутствует режимный байт).
Получилась программа Write_6.asm.

;********************************************************************************
; Write_6.asm ЗАПИСЬ В 24С64А МАССИВА БАЙТОВ
; (учебная, одноцикловая программа).
;--------------------------------------------------------------------------------
; Эта программа иллюстрирует невозможность осуществления записи (в пределах
; страницы) от текущего адреса.
;********************************************************************************
; "Практикум по конструированию устройств на PIC контроллерах".
; Автор: Корабельников Евгений Александрович
; http://ikarab.narod.ru karabea@lipetsk.ru
; Эта программа входит в состав 2-го подраздела 2-го раздела.
;********************************************************************************
; "Мастер" - PIC16F84A.
; "Помощник" - 24C64A.
; Кнопка пуска записи подключена к выводу RB0.
; Светодиод (индицирует конец цикла записи массива байтов) подключен к
; выводу RB1.
; Вывод RB6 подключен к линии такта (SCL).
; Вывод RB7 подключен к линии данных (SDA).
; Кварц 4 Мгц. (1м.ц.=1мкс.).
; Объем программы: 95 команд.
;********************************************************************************
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 ; Счетчик битов байта.
Inc_Data equ 0Eh ; Регистр хранения текущего байта данных.
Sec_L equ 10h ; Младший байт счетчика.
Sec_H equ 11h ; Старший байт счетчика.
;================================================================================
; "Привязка" названий битов регистров специального назначения к номерам битов.
;================================================================================

22
RP0 equ 5 ; Бит выбора банка.
C equ 0 ; Бит флага переноса-заёма.
Z equ 2 ; Бит нулевого результата.
SCL equ 6 ; Бит регистра PortB, который формирует такт.
SDA equ 7 ; Бит регистра PortB, который формирует данные.
;================================================================================
; Определение места размещения результатов операций.
;================================================================================
F equ 1 ; Результат направить в регистр.
W equ 0 ; Результат направить в аккумулятор.
;================================================================================
org 0 ; Начать выполнение программы с нулевогo адреса PC.
;********************************************************************************

;********************************************************************************
; "РАБОЧАЯ ЧАСТЬ" ПРОГРАММЫ.
;********************************************************************************
; Подготовительные операции.
;================================================================================
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 .0 ; Значение байта данных, записываемого в ячеку
movwf Inc_Data ; памяти с самым младшим (в пределах страницы) адресом.
;---------------------------------------------------
; Задание числового значения режимного байта.
;---------------------------------------------------
movlw B'10100000' ; Запись в регистр Temp режимного байта (1010-
movwf Temp ; код функциональности, 000–адрес м/схемы, 0– режим записи).
call BAIT_WR ; Условный переход в ПП обработки байта BAIT_WR.
;-----> Возврат по стеку из ПП BAIT_WR.

23
;---------------------------------------------------
; Задание числового значения старшего байта адреса.
;---------------------------------------------------
movlw .0 ; Запись в регистр Temp
movwf Temp ; старшего байта адреса.
call BAIT_WR ; Условный переход в ПП обработки байта BAIT_WR.
;-----> Возврат по стеку из ПП BAIT_WR.
;---------------------------------------------------
; Задание числового значения младшего байта адреса.
;---------------------------------------------------
movlw .0 ; Запись в регистр Temp
movwf Temp ; младшего байта адреса.
call BAIT_WR ; Условный переход в ПП обработки байта BAIT_WR.
;-----> Возврат по стеку из ПП BAIT_WR.
;---------------------------------------------------
; Задание числового значения байта данных.
;---------------------------------------------------
POVTOR movf Inc_Data,W ; Копирование содержимого текущего байта
movwf Temp ; данных из регистра Inc_Data в регистр Temp.
call BAIT_WR ; Условный переход в ПП обработки байта BAIT_WR.
;-----> Возврат по стеку из ПП BAIT_WR.
;--------------------------------------------------------------------------------
; Приращение содержимого байта данных (+1) перед его записью в следующую
; ячейку памяти.
;--------------------------------------------------------------------------------
incf Inc_Data,F ; Inc_Data + 1 = ...
movlw .16 ; Число .16, в данном случае, одновременно
; задает и количество записываемых байтов, и
; их числовые значения.
subwf Inc_Data,W ; Inc_Data - W = ... Результат - в W.
btfss Status,Z ; Результат вычитания равен или нет нулю?
goto POVTOR ; Нет, не равен - текущий байт данных записывается.
; Да, равен - формирование стоп-условия.
;================================================================================
; Формирование стоп-условия.
;================================================================================
bcf PortB,SDA ; SDA=0.
bsf PortB,SCL ; SCL=1.
bsf PortB,SDA ; SDA=1.
;================================================================================
; Задержка 5мс.
;================================================================================
clrwdt ; Сброс WDT.
movlw .125 ;
movwf Sec_L ; Запись констант
movlw .7 ; задержки.
movwf Sec_H ;

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


goto WR_1 ; вычитающий,
decfsz Sec_H,F ; 2-байтный
goto WR_1 ; счетчик.
;********************************************************************************
; Формирование старт-условия.
;================================================================================

24
bcf PortB,SDA ; SDA=0.
bcf PortB,SCL ; SCL=0.
;================================================================================
; "Администраторская" ПП (без названия), "рулящая" очередностью обработки байтов.
;================================================================================
movlw .0 ; Значение байта данных, записываемого в ячеку
movwf Inc_Data ; памяти с самым младшим (в пределах страницы) адресом.
;---------------------------------------------------
; Задание числового значения режимного байта.
;---------------------------------------------------
movlw B'10100000' ; Запись в регистр Temp режимного байта (1010-
movwf Temp ; код функциональности, 000–адрес м/схемы, 0– режим записи).
call BAIT_WR ; Условный переход в ПП обработки байта BAIT_WR.
;-----> Возврат по стеку из ПП BAIT_WR.
;---------------------------------------------------
; Задание числового значения байта данных.
;---------------------------------------------------
POVTOR_1 movf Inc_Data,W ; Копирование содержимого текущего байта
movwf Temp ; данных из регистра Inc_Data в регистр Temp.
call BAIT_WR ; Условный переход в ПП обработки байта BAIT_WR.
;-----> Возврат по стеку из ПП BAIT_WR.
;--------------------------------------------------------------------------------
; Приращение содержимого байта данных (+1) перед его записью в следующую
; ячейку памяти.
;--------------------------------------------------------------------------------
incf Inc_Data,F ; Inc_Data + 1 = ...
movlw .10 ; Число .10, в данном случае, одновременно
; задает и количество записываемых байтов, и
; их числовые значения.
subwf Inc_Data,W ; Inc_Data - W = ... Результат - в W.
btfss Status,Z ; Результат вычитания равен или нет нулю?
goto POVTOR_1 ; Нет, не равен - текущий байт данных записывается.
; Да, равен - формирование стоп-условия.
;================================================================================
; Формирование стоп-условия.
;================================================================================
bcf PortB,SDA ; SDA=0.
bsf PortB,SCL ; SCL=1.
bsf PortB,SDA ; SDA=1.
;================================================================================
; Задержка 5мс.
;================================================================================
clrwdt ; Сброс WDT.
movlw .125 ;
movwf Sec_L ; Запись констант
movlw .7 ; задержки.
movwf Sec_H ;

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


goto WR_2 ; вычитающий,
decfsz Sec_H,F ; 2-байтный
goto WR_2 ; счетчик.
;================================================================================
; Завершение полного цикла программы.
;================================================================================

25
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.
bsf PortB,SCL ; SCL=1. (Если в бите С 0, то предыдущая команда не
; исполняется. Вместо нее – "виртуальный" NOP).
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, то снова анализ (задержка до появления 0).
;--------------------------------------------------------------------------------
; Конец формирования импульса 9-го такта.
;--------------------------------------------------------------------------------
bcf PortB,SCL ; Если 0, то формируется спад импульса 9-го такта.
;--------------------------------------------------------------------------------
; Обратная перестройка направления работы вывода RB7.
;--------------------------------------------------------------------------------
bsf Status,RP0 ; Переход в 1-й банк.
bcf TrisB,SDA ; Вывод SDA работает на выход.
bcf Status,RP0 ; Переход в 0-й банк.

26
return ; Возврат по стеку в "администраторскую" ПП.
;********************************************************************************
end ; Конец программы.

Результат: записывается только 1-й массив байтов. 2-й массив байтов "дал дуба", и никакая
"реанимация" не помогает.
Вывод: запись от текущего адреса не возможна.
Общее замечание: программы Write... являются учебными, и они иллюстрируют
только принципы организации различных способов записи.
В части касающейся организации работы как с адресами, так и с байтами данных, они,
конечно же, далеки от совершенства.
Существует множество способов более сложной организации такого рода работы, но это
уже развитие темы.
На данном же этапе, нужно прочувствовать сам механизм записи и "врубиться" в его
суть, а "жировать" можно только после этого.
А вот теперь пришла пора "централизованного наведения порядка" в "записывающем
хозяйстве".
Итог по записи ("сухой осадок").

1. Все сигналы АСК являются "технологическими".


Для режимного байта и двух байтов адресного запроса, наличие сигналов АСК
свидетельствует о факте исполнения "помощником" действий (в порядке следования
этих байтов), определяемых их (байтов) функциональностью.
Для байтов данных, предназначенных для записи в память "помощника", наличие
сигналов АСК свидетельствует не о факте записи байтов данных в EEPROM память
"помощника", а о факте записи байтов данных в 32-байтную оперативную память
регистра данных "помощника".
Примечание: в данном случае, регистр данных конфигурируется (битом R/W) как 32-
байтная оперативная, буферная память.
2. "Плавающая" задержка применяется только при работе с флагом АСК, и ее
применение оправдано, так как, в данном случае, величина временных "промежутков",
между байтами любой функциональности, минимизируется.
3. Рис. 4 первого подраздела (предыдущего) 2-го раздела является универсальным и
отражает принцип формирования всех типов сигналов АСК (вырабатываемых под
байты любой функциональности).
Он заменяет "черновой" рисунок 5 второго подраздела 1-го раздела.
"Черновые" рисунки 3 и 4 второго подраздела 1-го раздела "похоронены", так как не
соответствуют действительности: запись в EEPROM происходит не после
"прохождения" байта данных, а после формирования стоп-условия.
4. Запись от текущего адреса не возможна. Любая процедура записи должна начинаться
(после старт-условия) с режимного байта.
5. Страница памяти содержит 256 страниц по 32 ячейки, а в переводе на блоки (в одном
блоке 8 страниц) - 32 блока.
6. Стоп-условие инициирует (в 24С64А) внутренний RC генератор (он начинает
работать), после чего осуществляется перезапись байтов из 32-байтного регистра
оперативной, буферной памяти ("накопителя") в ячейки ранее выбранной страницы
EEPROM памяти 24С64А.
Эта перезапись осуществляется "по верху" "старых" данных.
В это время, 24С64А не реагирует на внешние управляющие сигналы.

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

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

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

29
Куда подевался этот критерий? А ведь раньше он был.
Лично я, в этом усматриваю интеллектуальную трусость, в какие бы одежды она не
рядилась, и именно с этого начинается то, что я называю техническим "одебиливанием
нации", и против которого я так агрессивно настроен.
Надеюсь, что я не одинок в этой своей агрессивности, и подобного рода "защитная
реакция организма" имеется и у Вас.
Вернусь к своим "котлетам".
Пока они "жарятся", проведаю амнезийного бойца.
Зер гут! Всю миску выхлебал и даже щеки круглыми стали.
Глаза умные ... , но скрытое ехидство ощущается.
Ну что, раб Божий, наелся?
Ты что думаешь, на казенных хлебах, да в рай ...
Теперь кормежку отрабатывать нужно, а то "вбухано" в тебя много, а толку никакого, да
еще и ехидничаешь.
Завтра и далее, будет трудотерапия.
Видишь, в амбаре, соха лежит? Целину пахать будешь, причем, без лошади. Пока не
вспашешь десять соток, калорий не получишь, что в переводе на русский означает: что
толку от заполненных мозгов, если от этого нет практической отдачи.
В следующем подразделе "падаю" на чтение.

30
31