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

8/2.

Использование модуля MSSP, работающего в режиме I2C-ведущего, для


чтения массива байтов из EEPROM памяти м/схемы 24С64.

В данном случае, использую ту же тактику "зачисток".


То есть, анализирую "начинку" управляющих регистров модуля MSSP на предмет
востребованности их битов.
Регистр SSPStat - как было, так и осталось.
Регистр SSPCon1 - как было, так и осталось.
А вот в части касающейся регистра SSPCon2, произошло "расширение и углубление",
заключающееся во "вводе в эксплуатацию" трех его управляющих битов.
Эти биты выделены серыми рамками.

Если речь идет о том, что ведущий осуществляет чтение данных, "лежащих на
хранении" в аппаратных "дебрях" ведомого (осуществляет прием байтов, передаваемых
ведомым), то обязательно должен быть некий "рубильник", который включает/выключает
(запускает в работу/прекращает работу) режим чтения, а иначе "железяка" будет "глупо
моргать глазами" ("моя твоя не понимайт"), и на этом закончатся все "души
прекрасные порывы" ("любви не получилось").
В качестве такого "рубильника", используется бит RCEN.
Им нужно "клацнуть" непосредственно перед началом чтения.
Алгоритм этого "клацанья" настолько "детский", что я не решаюсь унижать Вас его
объяснением.

Управляющие биты ACKDT и ACKEN работают "в связке" и понятийно "отрывать их


друг от друга" нельзя.
С помощью битов ACKDT и ACKEN, осуществляется формирование отклика (сигнала
АСК) на прием ведущим байта, переданного ведомым.
То есть, после приема (чтения) ведущим байта, переданного ведомым, ведущий
должен сформировать отклик ("I2C-правила игры").
Этот отклик нужен для того, чтобы счетчик адреса ведомого автоинкрементировался.
А автоинкремент нужен для того, чтобы, в дальнейшем, обеспечить считывание байта,
"лежащего" в следующей ячеке памяти ведомого.
В целях пресечения возможного, понятийного "бардальеро", следует "глобально"
отметить, что существуют две разновидности сигнала АСК:
1
1. При передаче байта ведущим, сигнал АСК формирует ведомый (после
приема им байта), и этот сигнал принимается ведущим.
2. При приеме байта ведущим, сигнал АСК формирует ведущий (после
приема им байта), и этот сигнал принимается ведомым.

Если речь идет только о передаче байтов ведущим (см. предыдущий подраздел),
то имеет место быть разновидность сигнала АСК только 1-го пункта.
Если речь идет о приеме байтов ведущим, то имеет место быть разновидность
сигнала АСК и 1-го, и 2-го пунктов.
Последнее объясняется тем, что, прежде чем осуществить прием, нужно осуществить
передачу "рулежных" байтов: режимных (под передачу и под прием) и байтов адреса.

Вывод: в состав программы, в которой, по интерфейсу I2C, осуществляется


чтение байтов данных, должны входить и ПП передачи, и ПП приема.
ПП передачи задействуется при передаче "рулежных" байтов (от ведущего к
ведомому), а ПП приема задействуется при приеме ведущим байтов данных,
передаваемых ведомым (эта передача, и вообще, "все что шевелится в 24С64",
тактируется ведущим).
"Разборки" с ПП передачи были в предыдущем подразделе.
В этом подразделе, "упор будет сделан" на ПП приема.
В "границах" этой ПП, после приема ведущим байта, в соответствии с "I2C-правилами
игры", им (ведущим) должен быть сформирован сигнал АСК.
"За это ответственное I2C-дело отвечает" бит ACKEN.
Если бит ACKEN программно установить в 1, то после этого будет сформирован
сигнал АСК, подтверждающий прием ведущим байта данных.
После этого, программно сбрасывать бит ACKEN (в ноль) не нужно, так как он
сбрасывается автоматически (аппаратно).
Нужно только дождаться поднятия флага SSPIF, после чего можно "двигаться дальше".
И это есть "зер гут" ("гутее" просто не бывает).
Соответственно, если бит ACKEN в нуле, то о сигнале АСК 2-го пункта (см.
"вышележащую" таблицу) можно даже и не мечтать.
Теперь возникает вопрос о "рабочем" уровне сигнала АСК.
Его можно задать при помощи бита ACKDT.
Что в нем будет выставлено, то и будет уровнем сигнала АСК.
Можно выставить любой уровень (0 или 1), но "I2C-правила игры" требуют установки
нулевого уровня.
Поэтому, до входа в ПП приема, бит ACKDT должен быть сброшен в ноль.
Причем, это достаточно сделать только один раз.
Этот "малюсенький геморройчик" практически сводится на нет тем, что, в результате
любого сброса ПИКа (в том числе и по включению питания), в бите ACKDT
выставляется 0.
Проще говоря, по умолчанию, в бите ACKDT выставляется 0, и по этой причине, его
можно просто проигнорировать (но знать о нем нужно).
Это будет продемонстрировано ниже (даже "прописывать" этот бит не стал, так как
обращений к нему нет).
Не исключено то, что могут иметь место быть какие-то специфические случаи, когда
нужно "обкарнать" ("укоротить") сигнал АСК (во времени) или изменить его фазу, или
еще что-то с ним "схимичить", но какого-то большого практического смысла в этом,
лично я, пока (не стоит зарекаться), не вижу.
Итак, функции "таинственных незнакомцев" ясны и теперь можно "ваять" программу.
Но сначала нужно определиться с ее стратегией.
Она определяется "штатной" последовательностью действий I2C-протокола, в части
касающейся перехода ведущего в режим приема (чтения).
То есть, после передачи младшего байта адреса, должен быть сформирован
"Стоп/Старт", после чего должен быть передан второй, режимный байт с единицей в
младшем бите.
После получения отклика на режимный байт, рабочая точка программы должна
"влететь" в ПП (или группу команд) приема байтов от ведомого.
2
Предположим, что она "нормально" отработана.
Куда деть считанное? Ведь "погибнет же добро" (напоминаю про "кровь и пот")!
С оперативной памятью "каши не сваришь".
"Клацнул" тумблером, и все усилия "коту под хвост".
Значит нужно озаботиться "EEPROM-делами".
Короче, в данном случае, "сливки осядут" в первых 5-ти ячейках EEPROM памяти
данных PIC16F873A.
Можно "слить" их и в другую группу ячеек, но это уж Вы сами "сливайте" (какой
зададите адрес, туда и "сольете"), а я буду делать "единообразно и перпендикулярно"
(что поделаешь, последствия армейской школы. Кстати, совсем не плохие).
Самое главное - понять смысл, а все остальное - "обслуга".
Получилось сие "творение":

3
Процедуру записи в EEPROM память данных PIC16F873A я "врезал" в ПП приема
байтов, после чего "закольцевал" все это "безобразие" (конец à начало) через счетчик
принятых байтов.
Это позволяет обойтись без условных переходов и возвратов.
Ниже Вы видите, как это выглядит программно.
Примечание: принципиальная схема под эту "железяку" "лежит" в предыдущем
подразделе (ничего не изменилось).

;********************************************************************************
; RD_I2C.asm Чтение байтов данных из м/схемы памяти 24C64, с использованием
; модуля MSSP м/контроллера PIC16F873A
; (учебная программа)
;********************************************************************************
; "Практикум по конструированию устройств на PIC контроллерах"
; (http://ikarab.narod.ru) karabea@Lipetsk.ru
;================================================================================
; Автор: И.Н.Шевченко (RW1ZK), г.Заозерск Мурманская обл.
; (PIC18F252, 24C16).
; Е.А.Корабельников: перевод c PIC18F252 на PIC16F873A, с 24С16 на 24С64
; и объяснение работы.
;================================================================================
; Из 24С64 читается 5 байтов, но это количество можно изменить.
; Считанные байты записываются в первые 5 ячеек EEPROM памяти данных PIC16F873A.
; Линии SCL и SDA "подтянуты" к +5V через резисторы 4,7 Ком.
; Кварц 4 Мгц.
;================================================================================
; Функции выводов порта С:
; RC3 - линия SCL - вывод №6 24C64,
; RC4 - линия SDA - вывод №5 24C64,
; остальные выводы порта С не используются.
; Выводы портов А и В не используются.
;-----------------------------------------
; Объем программы: 84 команды.
;********************************************************************************
LIST p=16F873A ; Используется PIC16F873A.
__CONFIG 3F71h ; Включено: XT-генератор, PWRT, сброс BOR.
; Выключено: защита, WDT, LVP, DEBUG.
;================================================================================
; Регистры специального назначения.
;================================================================================
Status equ 03h ; Регистр Status.
SSPStat equ 14h ; Регистр статуса модуля MSSP (банк 1).
SSPCon equ 14h ; Регистр управления модуля MSSP.
SSPCon2 equ 11h ; Регистр управления модуля MSSP (банк 1).
SSPAdd equ 13h ; Регистр управления скоростью обмена
; (банк 1).
SSPBuf equ 13h ; Регистр приемо-передающего буфера.
PIR1 equ 0Ch ; Регистр флагов прерываний
; от периферийных модулей.
;--------------------------------------------
; Регистры управления EEPROM памятью данных.
;--------------------------------------------
EEAdr equ 0Dh ; Регистр адреса (банк 2).
EEData equ 0Ch ; Регистр данных (банк 2).
EECon1 equ 0Ch ; Управляющий регистр (банк 3).
EECon2 equ 0Dh ; Регистр, обеспечивающий защиту
; от случайной записи (банк 3).
;================================================================================
; Регистры общего назачения.
;================================================================================
Temp equ 20h ; Регистр временного хранения
; считанных байтов.
Byte equ 21h ; Счетчик байтов (он же - указатель адреса).

4
;================================================================================
; Присвоение битам названий.
;================================================================================
Z equ 2 ; Флаг нулевого результата.
RP0 equ 5 ; Бит выбора банка.
RP1 equ 6 ; Бит выбора банка.
SSPIF equ 3 ; Флаг прерывания от модуля MSSP.
SEN equ 0 ; Бит включения "Старта".
PEN equ 2 ; Бит включения "Стопа".
ACKSTAT equ 6 ; Бит подтверждения от ведомого.
SMP equ 7 ; Бит управления длительностью фронта.
RCEN equ 3 ; Бит разрешения/запрета приема.
ACKEN equ 4 ; Бит подтверждения ведущим приема байта.
;================================================================================
org 0 ; Начать выполнение программы
; с 0-го адреса PC.
;********************************************************************************

;********************************************************************************
; НАЧАЛО ПРОГРАММЫ.
;********************************************************************************
; Инициализация модуля MSSP (работа по I2C, режим ведущего, скорость 100 Кгц).
;================================================================================
; Все не задействованные модули отключены по умолчанию.
; Выводы всех портов, по умолчанию, работают на вход. По этой причине, не нужно
; подтверждать обязательную, в данном случае, настройку выводов RC3 (SCL) и
; RC4 (SDA) на работу "на вход".
; Все регистры SSP... , по умолчанию, сброшены в ноль. Прерывания запрещены.
; Обязательный, в данном случае, нулевой уровень отклика (сигнала АСК) на прием
; ПИКом байта, считанного из 24С64 (ACKDT=0), установлен по умолчанию.
;--------------------------------------------------------------------------------
bsf Status,RP0 ; Переход в 1-й банк.
movlw 9 ; Установка стандартной скорости обмена:
movwf SSPAdd ; Fosc/{4*(SSPAdd+1)}=4Мгц/40=100 Кгц.
bsf SSPStat,SMP ; Управление длительностью фронта выключено,
; т.к. выбрана стандартная скорость
; (100 Кгц.).
bcf Status,RP0 ; Переход в 0-й банк.

clrf Byte ; Сброс счетчика байтов.


movlw b'00101000' ; Включение модуля MSSP (SSPEN=1),
movwf SSPCon ; в режиме I2C-ведущего (SSPM3..SSPM0=1000).
;********************************************************************************
; Начало передачи массива байтов.
;********************************************************************************
; Формирование условия "START".
;================================================================================
call START ; Начало формирования условия "START".
;--->Возврат по стеку из ПП START
;================================================================================
; Передача режимного байта.
;================================================================================
movlw b'10100000' ; Передача режимного байта: 1010 - код
call WR_I2C ; функциональности, 000 - адрес м/схемы,
; 0 - режим записи.
;--->Возврат по стеку из ПП WR_I2C
;================================================================================
; Передача байтов адреса той ячейки 24C64, из которой будет считан 1-й байт
; массива. В данном случае, считывание начнется с 1-й ячейки (адрес 00h).
;================================================================================
movlw 0 ; Передача старшего
call WR_I2C ; байта адреса.
;--->Возврат по стеку из ПП WR_I2C
movlw 0 ; Передача младшего
call WR_I2C ; байта адреса.
5
;--->Возврат по стеку из ПП WR_I2C
;================================================================================
; Формирование условия "STOP".
;================================================================================
call STOP ; Начало формирования условия "STOP".
;--->Возврат по стеку из ПП STOP
;================================================================================
; Формирование условия "START".
;================================================================================
call START ; Начало формирования условия "START".
;--->Возврат по стеку из ПП START
;================================================================================
; Передача режимного байта.
;================================================================================
movlw b'10100001' ; Передача режимного байта: 1010 - код
call WR_I2C ; функциональности, 000 - адрес м/схемы,
; 1 - режим чтения.
;--->Возврат по стеку из ПП WR_I2C
;================================================================================
; ПП приема байта и формирования отклика ведущего на принятый байт.
;================================================================================
; Прием байта.
;-------------------------------------
RD_I2C bsf Status,RP0 ; Переход в 1-й банк.
bsf SSPCon2,RCEN ; Разрешение приема текущего байта
; от 24С64 (начало приема).
bcf Status,RP0 ; Переход в 0-й банк.

bcf PIR1,SSPIF ; Сброс флага перерываний от модуля MSSP.

btfss PIR1,SSPIF ; Прием текущего байта завершен или нет?


goto $-1 ; Если нет, то ожидание.
; Если завершен, то принятый байт аппаратно
; копируется в SSPBuf и программа исполняется
; далее.
movf SSPBuf,W ; Копирование принятого байта
movwf Temp ; из SSPBuf в Temp.
;++++++++++++++++++++++++++++++++++
; Принятый байт скопирован в Temp.
;----------------------------------------------------
; Формирование отклика ведущего.
;----------------------------------------------------
bsf Status,RP0 ; Переход в 1-й банк.
bsf SSPCon2,ACKEN ; Формирование подтверждения (АСК)
; принятого байта.
bcf Status,RP0 ; Переход в 0-й банк.

bcf PIR1,SSPIF ; Сброс флага перерываний от модуля MSSP.

btfss PIR1,SSPIF ; 9-й импульс закончился или нет?


goto $-1 ; Если нет, то ожидание.
; Если закончился, то программа
; исполняется далее.
;================================================================================
; Запись принятого байта в одну из ячеек EEPROM памяти данных PIC16F873A.
;================================================================================
; Анализ количества записываемых байтов.
;----------------------------------------------------
movlw 5 ; Задание количества записываемых байтов.
subwf Byte,W ; Byte - 5 = ...
btfsc Status,Z ; Записаны все 5 байтов или не все?
goto FINAL ; Если все, то запись заканчивается.
; Если не все, то программа
; исполняется далее.
;----------------------------------------------------
; Процедура записи в EEPROM память данных PIC16F873A.
6
;----------------------------------------------------
bcf Status,RP0 ; Переход
bsf Status,RP1 ; во 2-й банк.
movf Byte,W ;
movwf EEAdr ; Byte --> EEAdr.
movf Temp,W ;
movwf EEData ; Temp --> EEData.
bsf Status,RP0 ; Переход в 3-й банк.

bcf EECon1,7 ; Выбор режима записи в EEPROM память данных.


bsf EECon1,2 ; Разрешение записи.

movlw 55h ; Обязательная


movwf EECon2 ; процедура.
movlw 0AAh ; ---"---
movwf EECon2 ; ---"---
bsf EECon1,1 ; Инициализация записи.
bcf EECon1,2 ; Запрет записи.

btfsc EECon1,1 ; Запись завершена или нет?


goto $-1 ; Если нет, то ожидание.
bcf Status,RP0 ; Если завершена, то
bcf Status,RP1 ; переход в 0-й банк.
;----------------------------------------------------
; Подготовка к обработке следующего байта.
;----------------------------------------------------
incf Byte,F ; Byte + 1 = номер/адрес текущего байта.
goto RD_I2C ; Переход на начало обработки
; следующего байта.
;================================================================================
; Формирование условия "STOP".
;================================================================================
FINAL call STOP ; Начало формирования условия "STOP".
;--->Возврат по стеку из ПП STOP
;------------------------------------
; "Закончен бал, погасли свечи".
;------------------------------------
goto $ ; "Вечное, мертвое кольцо" (вместо него
; может быть продолжение программы).
;================================================================================
; ПП передачи байта и анализа отклика ведомого.
;================================================================================
POVTOR bcf Status,RP0 ; Переход в 0-й банк.
WR_I2C movwf SSPBuf ; Загрузка буфера байтом любой
; функциональности (начало передачи
; текущего байта).
bcf PIR1,SSPIF ; Сброс флага перерываний от модуля MSSP.

btfss PIR1,SSPIF ; Передача текущего байта завершена или нет?


goto $-1 ; Если нет, то ожидание.
; Если завершено, то программа
; исполняется далее.
;------------------------------------
; Анализ отклика ведомого.
;------------------------------------
bsf Status,RP0 ; Переход в 1-й банк.
btfsc SSPCon2,ACKSTAT; Подтверждение от ведомого (ACK) есть
; или нет?
goto POVTOR ; Если нет, то повтор передачи текущего байта
bcf Status,RP0 ; Если есть, то переход в 0-й банк,
return ; после чего - возврат по стеку.
;================================================================================
; ПП формирования условия "START".
;================================================================================
START bcf PIR1,SSPIF ; Сброс флага перерываний от модуля MSSP.

7
bsf Status,RP0 ; Переход в 1-й банк.
bsf SSPCon2,SEN ; Начало формирования условия "START".
bcf Status,RP0 ; Переход в 0-й банк.

btfss PIR1,SSPIF ; Формирование условия "START" завершено


; или нет?
goto $-1 ; Если нет, то ожидание.
return ; Если завершено, то возврат по стеку.
;================================================================================
; ПП формирования условия "STOP".
;================================================================================
STOP bcf PIR1,SSPIF ; Сброс флага перерываний от модуля MSSP.

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


bsf SSPCon2,PEN ; Начало формирования условия "STOP".
bcf Status,RP0 ; Переход в 0-й банк.

btfss PIR1,SSPIF ; Формирование условия "STOP" завершено


; или нет?
goto $-1 ; Если нет, то ожидание.
return ; Если завершено, то возврат по стеку.
;********************************************************************************
end ; Конец программы.

Работа программы
Вплоть до окончания передачи младшего байта адреса, все то же самое (см.
предыдущий подраздел).
Единственное замечание: бит ACKDT сброшен в 0 по умолчанию.
А раз это так, то, не смотря на его "боевые заслуги", он вообще "лишен прописки и
удален за 101-й километр" (прошу не путать с проститутками. Это "парень" достойный.
Просто оказался не нужным).

;================================================================================
; Формирование условия "STOP".
;================================================================================
call STOP ; Начало формирования условия "STOP".
;--->Возврат по стеку из ПП STOP
;================================================================================
; Формирование условия "START".
;================================================================================
call START ; Начало формирования условия "START".
;--->Возврат по стеку из ПП START
;================================================================================
; Передача режимного байта.
;================================================================================
movlw b'10100001' ; Передача режимного байта: 1010 - код
call WR_I2C ; функциональности, 000 - адрес м/схемы,
; 1 - режим чтения.
;--->Возврат по стеку из ПП WR_I2C

"Стоп/Старт" (см. "I2C-правила игры") формируется стандартно.


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

Теперь можно читать:


;================================================================================
; ПП приема байта и формирования отклика ведущего на принятый байт.
;================================================================================

8
; Прием байта.
;-------------------------------------
RD_I2C bsf Status,RP0 ; Переход в 1-й банк.
bsf SSPCon2,RCEN ; Разрешение приема текущего байта
; от 24С64 (начало приема).
bcf Status,RP0 ; Переход в 0-й банк.

bcf PIR1,SSPIF ; Сброс флага перерываний от модуля MSSP.

btfss PIR1,SSPIF ; Прием текущего байта завершен или нет?


goto $-1 ; Если нет, то ожидание.
; Если завершен, то принятый байт аппаратно
; копируется в SSPBuf и программа исполняется
; далее.
movf SSPBuf,W ; Копирование принятого байта
movwf Temp ; из SSPBuf в Temp.
;++++++++++++++++++++++++++++++++++
; Принятый байт скопирован в Temp.
;----------------------------------------------------
; Формирование отклика ведущего.
;----------------------------------------------------
bsf Status,RP0 ; Переход в 1-й банк.
bsf SSPCon2,ACKEN ; Формирование подтверждения (АСК)
; принятого байта.
bcf Status,RP0 ; Переход в 0-й банк.

bcf PIR1,SSPIF ; Сброс флага перерываний от модуля MSSP.

btfss PIR1,SSPIF ; 9-й импульс закончился или нет?


goto $-1 ; Если нет, то ожидание.
; Если закончился, то программа
; исполняется далее.

Чтение текущего байта начинается с разрешения приема (bsf SSPCon2,RCEN).


Внимание!
При чтении массива байтов (как в данном случае), каждый раз нужно разрешать
прием.
То есть, команда bsf SSPCon2,RCEN должна быть "врезана" во внутренний цикл ПП
приема (должна исполняться на каждом "витке").
"Выносить" ее из этого внутреннего цикла (например, исполнить "на подлете") нельзя,
иначе считается только первый байт массива, а остальные "погибнут".
Вопрос: "Почему именно так, а не эдак"?
Ответ: потому, что команда bsf SSPCon2,RCEN "запускает в работу" процедуру чтения
одного байта (текущего).
После этого, чтение байта будет произведено аппаратно (автоматически).
Соответственно, если не исполнить эту команду, то и никакого чтения не будет.
Короче, "с какого бока не смотри", а "важняк есть важняк" ("курок у пистолета").
После этого "запуска", нужно просто-напросто сбросить флаг SSPIF и дождаться
отработки "плавающей" задержки.
А теперь оцените "сервис": байт принят без Вашего участия (за исключением "нажатия
на курок") !!!
Он "осядет" в регистре SSPBuf ("блюдечко с голубой каемочкой"), после чего, с этим
байтом (вернее, с его числовым значением) "можно вытворять все что угодно".
Как говорится, без комментариев (нет слов. Одни !!!).
В данной программе, считанный (текущий) байт "помещается на временное хранение" в
регистр Temp, из которого он, позднее, будет переписан в EEPROM память данных
PIC16F873A.
Но это еще не весь "сервис".
Отклик ведущего (АСК) также формируется в "полуавтомате".
То есть, нужно только инициировать отклик (bsf SSPCon2,ACKEN) и дождаться
окончания импульса 9-го такта (аппаратно вырабатывается под сигнал АСК).

9
При этом, в "плавающей" задержке, задействуется все тот же "легендарный" флаг
SSPIF (самый натуральный "универсал").
Итак, байт считан ("лежит" в регистре Temp) и ведущий сформировал отклик.
При этом, "крови почти не пролито", плюс, отсутствие "возни с фазой/временем".
По-моему, "получилась могучая (наш губернатор это слово очень любит) любовь" и
можно расчитывать на "румяных карапузов".

Теперь нужно записать считанный байт в ячейку EEPROM памяти данных PIC16F873A.
Байт есть, но нужно записать его не "абы как", а в конкретную ячейку, с конкретным
адресом.
Следовательно, нужно "поставить подпрограмму на счетчик", то есть, организовать
внутреннее кольцо счета.
В данном случае, это делается достаточно стандартно, но с совмещением функций.
Под это дело назначен регистр Byte.

Byte equ 21h ; Счетчик байтов (он же - указатель адреса).

Он одновременно является и счетчиком обрабатываемых байтов, и указателем адреса


той ячейки EEPROM памяти данных PIC16F873A, в которую будет записан текущий
байт, считанный из памяти 24С64.

;********************************************************************************
; НАЧАЛО ПРОГРАММЫ.
;********************************************************************************
; Инициализация модуля MSSP (работа по I2C, режим ведущего, скорость 100 Кгц).
;================================================================================
................................
clrf Byte ; Сброс счетчика байтов.
................................
;================================================================================
; ПП приема байта и формирования отклика ведущего на принятый байт.
;================================================================================
; Прием байта.
;-------------------------------------
RD_I2C bsf Status,RP0 ; Переход в 1-й банк.
................................
;================================================================================
; Запись принятого байта в одну из ячеек EEPROM памяти данных PIC16F873A.
;================================================================================
; Анализ количества записываемых байтов.
;----------------------------------------------------
movlw 5 ; Задание количества записываемых байтов.
subwf Byte,W ; Byte - 5 = ...
btfsc Status,Z ; Записаны все 5 байтов или не все?
goto FINAL ; Если все, то запись заканчивается.
; Если не все, то программа
; исполняется далее.
;----------------------------------------------------
; Процедура записи в EEPROM память данных PIC16F873A.
;----------------------------------------------------
................................
;----------------------------------------------------
; Подготовка к обработке следующего байта.
;----------------------------------------------------
incf Byte,F ; Byte + 1 = номер/адрес текущего байта.
goto RD_I2C ; Переход на начало обработки
; следующего байта.
;================================================================================
; Формирование условия "STOP".
;================================================================================
FINAL call STOP ; Начало формирования условия "STOP".
................................

10
В начале программы, содержимое регистра Byte сбрасывается в ноль (подготовка к
счету).
После того, как будет отработана ПП приема байта и формирования отклика
ведущего на принятый байт, из числа, "лежащего" в регистре Byte, вычитается
заданное количество обрабатываемых байтов (5), после чего производится проверка
нулевого результата операции вычитания.
Если результат не равен 0, то текущий байт (Temp) записывается в EEPROM память
данных PIC16F873A, в ячейку с адресом, "лежащим" в регистре Byte.
После выхода из процедуры записи, производится инкремент содержимого регистра
Byte и отрабатывается новый цикл чтения.
И так далее.
На 5-м "витке" внутреннего цикла, будет получен нулевой результат вычитания, после
чего формируется условие "STOP" и программа благополучно "зависает" на команде
goto $ (напоминаю, что программа одноцикловая).
В итоге, в 1-ю ячеку EEPROM памяти данных PIC16F873A, будет записано числовое
значение 1-го, считанного из 2464А, байта, во 2-ю - 2-го … в 5-ю - 5-го, в порядке

11h 22h 33h 44h 55h

Теперь "падаю" на процедуру записи в EEPROM память данных PIC16F873A.


Как таковая, эта процедура не имеет прямого отношения к "MSSP-делам", но
"разглядеть ее поближе" стоит, так как имеется "PIC16F8xx-специфика".
- "банковская",
- "типоEEPROMная".
"Банковская" специфика состоит в том, что регистры управления EEPROM памятью
данных "лежат" не в привычных 0-м и 1-м банках, а во 2-м и 3-м банках.
Поэтому нужно организовать соответствующие переходы из банка в банк.
"ТипоEEPROMная" специфика состоит в том, что, кроме записи в EEPROM память
данных / чтения из EEPROM памяти даных, можно осуществить запись в EEPROM
память программ / чтение из EEPROM памяти программ.
Замечание по ходу дела: последнее "открывает шлагбаум" для "самомодификации"
программы (!!!), что есть совсем не слабо и очень заманчиво. Можно "наворочать
такое…". Бог даст, "просканирую" (всему свое время).
А пока, нужно "дожарить текущие котлеты".
Итак, имеется "рубильник", посредством "клацанья" которым, происходит выбор режима
работы с тем или иным типом EEPROM памяти.
Этот "рубильник" есть бит EEPGD (№7) регистра EECon1.
В данном случае, его нужно сбросить в 0.
Не мудрствуя лукаво, я использовал "даташитную" процедуру записи, но переместил
"плавающую" задержку из "верха" процедуры записи, в ее "низ".
Так более привычно, хотя, если разобраться, то "плавающая" задержка, размещенная
на "входе" процедуры записи, имеет свой большой плюс.
В этом случае, за счет одновременного "делания двух дел", уменьшается время
отработки полного цикла программы.
Напоминание: после "запуска в работу" процедуры записи байта в EEPROM память
данных, эта запись происходит аппаратно.
Например.
Пусть запись одного байта происходит за 4 мс., а остальной цикл программы
отрабатывается за 3 мс.
В случае "дислокации" "плавающей" задержки в конце процедуры записи, полный цикл
программы будет отработан за время 3 + 4 = 7 мс. (последовательное "делание двух
дел").
В случае "дислокации" "плавающей" задержки в начале процедуры записи, полный цикл
программы будет отработан за время 3 + (4 – 3) = 4 мс. (одновременное, в течение
3-х мс, "делание двух дел").
Если же этот "остальной цикл программы" будет отрабатываться за время большее
чем время записи байта, то "плавающая" задержка будет отработана "с реактивным
свистом (быстрый "проскок транзитом" "плавающей" задержки).
11
Проще говоря, задержка в 4 мс. отработается по ходу отработки полного цикла
программы.
Поэтому, к моменту входа рабочей точки программы в "новую" процедуру записи, флаг
WR будет опущен (WR = 0: предыдущая запись завершена и можно начинать "новую"
запись).
Руководствуясь принципом "от простого к сложному" ("всему свое время"), ранее, я не
считал целесообразным акцентировать Ваше внимание на этой специфике.
До достижения определенного уровня "матерости" (на уровне рефлексов), о "технике
безопасности" всегда нужно помнить.
На мой взгляд, ожидание, в конце того, что началось, окончания того, что
началось, более привычно и понимаемо, чем ожидание, в начале того, что еще не
началось, окончания того, что началось ранее, и что, на момент начала анализа,
может либо закончиться, либо не закончиться (требуется расчет).
Но это вовсе не говорит о том, что привычное есть самое эффективное.
Тем не менее, "двигаться" к самому эффективному нужно именно от привычного, иначе
есть большой риск возникновения различных понятийных "бяк", вплоть до полного
"бардальеро" и даже до непонимания того, что раньше было понятно.
А вообще, это правило старо как мир, но не смотря на это, нарушается сплошь и
рядом.
"Сухой осадок": если нужно минимизировать время исполнения полного цикла
программы, в состав которой входит процедура записи в EEPROM память
данных, то "плавающую" задержку нужно поместить в начало процедуры записи.
То же самое относится не только к записи одного байта, но и к записи массива
байтов.
В рассматриваемом случае, эта минимизация не нужна, и поэтому я поместил
"плавающую" задержку в конец процедуры записи.

"Механика" работы с устройством такая.


В первые 5 ячеек 24С64 записываете 11 22 33 44 55 (или то, что Вам нравится).
Вставляете 24С64 в устройство.
"Шьете" PIC16F873A.
После этого, во всех ячейках его EEPROM памяти данных, будут записаны числа FFh.
Вставляете ПИК в устройство.
Включаете питание устройства.
Выключаете питание устройства (цикл программы отрабатывается быстро).
Читаете PIC16F873A и убеждаетесь, что в первые 5 ячеек его EEPROM памяти
данных записалось 11 22 33 44 55.
После "перепрошивания" ПИКа, "по верху" всех этих чисел, записывается FF, и можно
повторить.

Ну и ладушки.
По ходу дела, последовательно, "двух зайцев прихлопнул".
А в дали еще один "маячит" (кто ищет приключений, тот их всегда найдет).
Спрятался, но уши из-за куста торчат. Это их слабый и предательский орган.
Что-то типа Ахиллесовой пяты.
Ух какой матерый и жирный!
Ну я побежал.
В следующем подразделе "угощу свежей зайчатинкой".

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

12

Оценить