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

8/1. Общие положения. Выбор направления "вектора тяги".

Работа модуля
MSSP по интерфейсу I2C, в режиме ведущего. Учебное устройство записи
массива байтов в 24С64.

Если разработчики подсуетились и "сваяли" модуль с таким интригующим названием


(модуль ведущего, синхронного, последовательного порта), то эта "штуковина", по идее,
должна как-то облегчить многострадальную жизнь конструктора, а иначе зачем "ваять"?
Открываю даташит. Читаю…
Ничего себе облегчение!
Одних "кнопочек" ("управлялок") как блох на собаке, не говоря об остальном (умные
слова и картинки со смысловой "компрессией" и т.п.).
В подобных случаях, не стоит "бросаться на все сразу", а нужно срочно "сужать
сектор обстрела", иначе есть большой риск банально запутаться.
Пояснение: высокое звание "гомо сапиенса" настоятельно обязывает.
Поэтому, объявляю "всеобщую мобилизацию", с вызовом всех летающих коров, сбором
всех шпионов (своих, проверенных. Чужих "убиваю"), выкатыванием из сарая гаубицы и
т.д.
Для того, чтобы от работы (любой) был толк, нужно сформулировать конкретную
задачу, но она, на "голом месте", как-то плоховато формулируется.
Значит, изначально, следует разобраться с "глобальными" функциями модуля MSSP.
Модуль MSSP есть модуль, обеспечивающий работу по последовательному интерфейсу.
Значит, в "глобальном" смысле, модуль MSSP "одним миром мазан" с модулем
USART.
Разница только в типах интерфейсов.
Модуль MSSP обеспечивает работу аж по двум типам последовательных интерфейсов:
- по интерфейсу SPI,
- по интерфейсу I2C.
Интерфейс SPI есть "дедушка, доживающий свой век".
В основе принципа работы по интерфейсу SPI, лежит простой подсчет количества
битов байта (8).
"Старта"/"стопа" нет, да еще и 4 "проволочины" (с учетом "земли").
Короче, "антиквариат", хотя, для обмена данными между ПИКами, его вполне можно
использовать (на худой конец).
В современных условиях, он как-то не актуально смотрится, да и зачем "старика
мучать"?
Пускай "лежит на печке и кости греет".
"Бабу (вернее, деда) с воза - кобыле легче". И еще как!
То ли дело интерфейс I2C.
Как говорится, "румяный парень в самом расцвете сил", да еще с "гармонью и
кудрявым чубом" (на "свадьбы и гулянки" зовут, наливают, и девушки любят. Поэтому
и разбалованный).
Сам по себе, он "парень" не плохой, но строптивый и привередливый.
К таким "парням" особый подход нужен (а куда деваться? В сердцах, так и огрел бы
красавчика, да заменить некем).
Поэтому и был написан 1-й раздел "Практикума…".
С большой радостью отмечаю то, что он был написан не зря, так как мало того, что
нашлись люди, которые в него "въехали", но и нашлись люди, которые самостоятельно
"поехали" дальше (имею ввиду наших).
И "поехали" так так резво и успешно, что мне ничего другого не остается, как
объяснить то, что ими уже наработано.
Речь идет о работе Ивана Шевченко.
Когда я поближе с ней познакомился, стало ясно, что Иван "разгрыз этот орешек" и
"грызть" мне особо нечего.
"Снимаю шляпу", так как полностью отдаю себе отчет и в достаточно высоком уровне
этих "разборок", и в объеме сопровождающей их "пахоты".
Мне нужно просто объяснить, "откуда ноги растут", и кое-что
добавить/уточнить/скорректировать (по тактике).

1
По большому счету, Иван сработал как "таран" (кстати, на свой страх и риск), что
внушает и уважение, и большой оптимизм, ведь я доподлинно знаю, что было раньше
и что есть сейчас, а также и могу предположить, что будет в будущем.
Прошу учесть, что информация раздела, посвященного модулю MSSP, базируется на
работе Ивана Шевченко, которую я, поставив себя на место Ивана, буду объяснять (в
меру своей испорченности и своих возможностей) поэтапно.
Не исключено "углубление и расширение" (выяснится по ходу дела).
А теперь ближе к делу.
Итак, последовательный интерфейс SPI в расчет не беру (будем считать, что "дедушка
дожил до дембеля").
Соответственно, количество "управленцев" резко сократилось.
Уже значительно легче ("бюрократия страшнее атомной войны").
Почти все оставшиеся "управленцы окопались" в управляющих регистрах модуля MSSP:
- в регистре статуса модуля MSSP: SSPStat,
- и еще в 2-х управляющих регистрах: SSPCon и SSPCon2.
В рассматриваемом случае, интерес представляют только те их биты, которые
"привязаны" к интерфейсу I2C.
После ознакомления с технической документацией (работаю с PIC16F873A), выясняется,
что модуль MSSP может работать в двух режимах:
- ведущего ("мастера") или
- ведомого ("помощника").
Теперь, в соответствии с принципом "разделяй и властвуй", нужно определиться, к
какому из этих режимов "прислониться".
На мой взгляд, изначально, выгоднее "раскрутить" режим ведущего.
Итак, ПИК, по интерфейсу I2C, чем-то будет "рулить".
Не буду особо мудрить, а в качестве "раба", применю то, что было использовано
ранее, то есть, м/схему EEPROM памяти 24С64.
Окончательно формулирую конкретную задачу: необходимо, с помощью модуля MSSP
PIC16F873A, работающего в режиме ведущего, записать массив из, например, 5-ти
байтов данных, в первые 5 ячеек памяти м/схемы 24С64.
Теперь нужно "обратить взор" на управляющие регистры модуля MSSP, и с учетом
того, что режим SPI не используется, и того, что модуль MSSP работает в режиме
ведущего, "выбраковать" те их биты, которые, в данном случае, не используются.
То, что останется после этой "чистки", и будет "сухой осадок" (это и есть "сужение
сектора обстрела"). Получилось вот что:

Бит SMP - управление длительностью фронта.


Эта настройка связана с необходимостью соблюдения предельных временных
характеристик шины I2C в части касающейся длительности фронта.
Это чисто "технологический прибамбас", таинства которого известны только
разработчикам (они их не афишируют).
Такие "правила игры" просто нужно принять как данность.
Имеются 3 стандартные скорости обмена данными: 100 Кгц, 400 Кгц, 1 Мгц (в
частотном выражении).
Если используются скорости 100 Кгц, 1 Мгц, то в бите SMP нужно выставить 1, а если
используется скорость 400 Кгц, то 0.
2
К Вашему сведению: на скорости 100 Кгц, я пробовал и 0, и 1.
Это ни к чему плохому не привело. В обеих случаях, устройство работало одинаково.

Бит CKE - выбор спецификации входных уровней.


Тут все однозначно: нужно выставлять 0.

Остальные биты регистра SSPStat являются "индикаторными" (флаги, указатели).


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

Бит SSPEN - бит включения модуля MSSP.


По-моему, комментировать нечего. Его функция предельно ясна.

Биты SSPM3…SSPM0 - биты выбора режима работы модуля MSSP.


Существует единственный режим работы модуля MSSP, при котором, для его
тактирования, используется внутренний такт ПИКа.
Он и выбран ("дешево и сердито". Самый "ходовой" вариант).
Формулой
Fosc/{4x(SSPAdd+1)}
задается скорость обмена.
Например, для того чтобы, при использовании кварца на 4 Мгц, обеспечить
стандартную скорость обмена 100 Кгц (в частотном выражении), нужно записать, в
регистр SSPAdd (1-й банк, адрес 93h), число .9.
При этом, и период такта (SCL), и время "прохождения" одного бита данных (SDA)
будут равны по 10 мкс.
Можно задать и нестандартную скорость обмена.

3
Состояние бита CKP, в данном случае (режим ведущего), не имеет значения.
Биты WCOL и SSPOV - биты "непонимаек".
Если на шине I2C находятся только 2 устройства (как в рассматриваемом случае),
действия производятся строго последовательно/"штатно" и скорость обмена не
"задрана", то об этих битах можно "забыть".

Бит ACKSTAT - бит подтверждения от ведомого.


Если, после передачи байта ведущим, ведомый принял этот байт без ошибок, то на
линию SDA, со стороны ведомого, выдается уровень сигнала АСК (0, если байт принят
без ошибок или 1, если байт принят с ошибками).
Этот уровень и записывается (аппаратно) в бит ACKSTAT.
При этом, никаких программных перестроек направления работы вывода порта,
подключенного к линии SDA, производить не нужно, так как эти "дела делаются"
аппаратно (автоматически).
Нужно просто "глянуть" в бит ACKSTAT и сделать соответствующие "оргвыводы".
Кто скажет, что это не есть "зер гут"?

Бит SEN - бит формирования условия "START".


Для того чтобы сформировать условие "START" (сформировать стартовый бит), нужно
только выставить в бите SEN единицу и дождаться окончания формирования условия
"START".
Модуль MSSP все сформирует "в лучшем виде".

Бит PEN - бит формирования условия "STOP".


Аналогично формированию условия "START".

Бит GCEN работает только в режиме ведомого.

Биты ACKDT и ACKEN нужны для обеспечения формирования ведущим сигнала ACK,
выдаваемого на линию SDA после принятия байта данных от ведомого (при чтении из
24С64).
В данном случае, "их услуги" не требуются (чтения не производится).

Бит RSEN - бит формирования условия "Повторный START".


Необходимость в формировании условия "Повторный START" возникает тогда, когда, в
одном цикле передачи (то есть, не дожидаясь "Стопа"), нужно переадресоваться к
ячейке EEPROM памяти 24С64 (в данном случае), имеющей адрес отличный от адреса
текущей ячейки.
То есть, с помощью этого условия, можно прервать (до "Стопа") запись массива
байтов в один "сектор" EEPROM памяти и продолжить запись этого массива (или
записать другой массив байтов) в другой "сектор" EEPROM памяти 24С64.
Условие "Повторный START" нужно формировать сразу же после успешного
завершения анализа отклика (АСК = 0), полученного от ведомого.
4
После этого, ведущий последовательно передает байты адреса и байты массива
байтов данных (режимный байт передавать не нужно).
Но в данном случае, этого не требуется.

Условие "Передача байта" формируется сразу же после окончания записи байта


(любой функциональности), предназначенного для передачи, в регистр специального
назначения SSPBuf (0-й банк, адрес 13h).
То есть, для того чтобы передать байт, не нужно программно формировать
соответствующие импульсные последовательности на линиях SCL и SDA (то, о чем
говорилось в 1-м разделе), а нужно всего-навсего произвести запись этого байта в
регистр SSPBuf.
После этого, модуль MSSP "все сделает в лучшем виде" (аппаратно), вплоть до
окончания передачи байта (конструктор не напрягается, курит папироску и радуется
жизни).
Нужно только дождаться окончания этой процедуры.

Итак, получается, что конструктор имеет возможность:

1. Установкой бита SEN в 1, сформировать условие "START",


2. Записью байта, предназначенного для передачи, в регистр SSPBuf, сформировать
условие "Передача байта",
3. Чтением бита SSPSTAT, определить, имеет или не имеет место быть сигнал
подтверждения ведомым приема байта (АСК),
4. Установкой бита PEN в 1, сформировать условие "STOP" (при наличии АСК.
При отсутствии АСК - повтор передачи байта).

С "запуском" (началом) процедур все понятно.


Но если есть начала (множественное число), то должны быть и соответствующие
концы (в прямом, а не в переносном смысле!!!). Диалектика…
А так как все дела в этом мире делаются во времени, то нужно дождаться того или
иного, конкретного конца.
Тогда возникает вопрос: "Каков критерий подсиживания/пережидания"?
Ответ на этот вопрос "упирается" в такого "важняка", как флаг прерываний от модуля
MSSP с названием SSPIF (бит №3 регистра PIR1, 0-й банк, адрес 0Ch).
Этот флаг "живуч" и "шевелится" (работает) вне зависимости от того, разрешены
прерывания от модуля MSSP или нет.
Флаг SSPIF является универсальным в том смысле, что он поднимается не только
сразу же после окончания отработки процедур пунктов 1, 2, 4, но и сразу же после
отработки условия "Повторный START", и при обнаружении формирования условий
"START" или "STOP" (последнее относится к режиму работы с несколькими ведущими).
Что касается пункта 3, то одновременно с поднятием флага SSPIF (он поднимается в
конце 9-го такта, то есть, после гарантированной установки, на линии SDA, уровня
сигнала АСК), происходит запись уровня сигнала АСК в бит ACKSTAT.
Таким образом, сразу же после поднятия флага SSPIF, можно производить анализ
уровня сигнала АСК и "ветвиться" на сценарии.
Примечание: в случае передачи байта, достаточно только тех 4-х пунктов, которые
упомянуты выше.
С учетом сказанного, при передаче байта, последовательность действий должна
выглядеть так (без учета инициализации модуля MSSP):

Опустить флаг SSPIF.


1. Установкой бита SEN в 1, сформировать условие "START".
Перейти в "плавающую" задержку, работающую с флагом SSPIF.
После ее отработки, условие "START" сформировано, и можно передавать байт.
Опустить флаг SSPIF.
Записью байта, предназначенного для передачи, в регистр SSPBuf, сформировать
2. условие "Передача байта".
Перейти в "плавающую" задержку, работающую с флагом SSPIF.
После ее отработки, байт передан, уровень сигнала АСК записан в бит SSPSTAT
5
и этот бит можно читать.
После чтения бита SSPSTAT, определить, имеет или не имеет место быть
сигнал подтверждения ведомым приема байта (АСК), и в зависимости от этого,
3. выбрать один из двух сценариев:
- переход к формированию условия "STOP",
- повторная передача байта.
В случае исполнения 1-го сценария, опустить флаг SSPIF, и установкой бита
PEN в 1, сформировать условие "STOP".
4. Перейти в "плавающую" задержку, работающую с флагом SSPIF.
После ее отработки, условие "STOP" сформировано, и можно либо продолжить
работу, либо перейти ждущий режим (SCL = SDA = 1).

И никакого "программного геморроя" и "возни" с фазой/временем.


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

Так как модуль MSSP расчитан на работу по протоколу I2C, имеют место быть
выходные каскады с открытым коллектором, и поэтому линии SCL и SDA должны
быть "подтянуты" резисторами к плюсу источника питания, что Вы и видите.

;********************************************************************************
; WR_I2C.asm Запись байтов данных в м/схему памяти 24C64, с использованием
; модуля MSSP м/контроллера PIC16F873A
; (учебная программа)
;********************************************************************************
; "Практикум по конструированию устройств на PIC контроллерах"
; (http://ikarab.narod.ru) karabea@Lipetsk.ru
6
;================================================================================
; Автор: И.Н.Шевченко (RW1ZK) 08.08.2007, г.Заозерск Мурманская обл.
; (PIC18F252, 24C16).
; Е.А.Корабельников: перевод c PIC18F252 на PIC16F873A, с 24С16 на 24С64
; и объяснение работы.
;================================================================================
; Записывается 5 байтов, но это количество можно изменить.
; Линии SCL и SDA "подтянуты" к +5V через резисторы 4,7 Ком.
; Кварц 4 Мгц.
;================================================================================
; Функции выводов порта С:
; RC3 - линия SCL - вывод №6 24C64,
; RC4 - линия SDA - вывод №5 24C64,
; остальные выводы порта С не используются.
; Выводы портов А и В не используются.
;-----------------------------------------
; Объем программы: 55 команд.
;********************************************************************************
LIST p=16F873A ; используется PIC16F873A.
__CONFIG 3F71h ; Включено: XT-генератор, PWRT, сброс BOR.
; Выключено: защита, WDT, LVP, DEBUG.
;================================================================================
; Регистры специального назначения.
;================================================================================
Status equ 03h ; Регистр Status.
IndF equ 00h ; Доступ к памяти через FSR.
FSR equ 04h ; Регистр косвенной адресации.
SSPStat equ 14h ; Регистр статуса модуля MSSP (банк 1).
SSPCon equ 14h ; Регистр управления модуля MSSP.
SSPCon2 equ 11h ; Регистр управления модуля MSSP (банк 1).
SSPAdd equ 13h ; Регистр управления скоростью обмена
; (банк 1).
SSPBuf equ 13h ; Регистр приемо-передающего буфера.
PIR1 equ 0Ch ; Регистр флагов прерываний
; от периферийных модулей.
;================================================================================
; Регистры общего назачения.
;================================================================================
Temp1 equ 20h ; Регистры
Temp2 equ 21h ; хранения
Temp3 equ 22h ; байтов,
Temp4 equ 23h ; предназначенных
Temp5 equ 24h ; для записи.
Byte equ 25h ; Счетчик байтов.
;================================================================================
; Присвоение битам названий.
;================================================================================
RP0 equ 5 ; Бит выбора банка.
SSPIF equ 3 ; Флаг прерывания от модуля MSSP.
SEN equ 0 ; Бит включения "Старта".
PEN equ 2 ; Бит включения "Стопа".
ACKSTAT equ 6 ; Бит подтверждения от ведомого.
SMP equ 7 ; Бит управления длительностью фронта.
;================================================================================
org 0 ; Начать выполнение программы
; с 0-го адреса PC.
;********************************************************************************

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

movlw b'00101000' ; Включение модуля MSSP (SSPEN=1),


movwf SSPCon ; в режиме I2C-ведущего (SSPM3..SSPM0=1000).
;********************************************************************************
; Начало передачи массива байтов.
;********************************************************************************
; Формирование условия "START".
;================================================================================
bcf PIR1,SSPIF ; Сброс флага перерываний от модуля MSSP.

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


bsf SSPCon2,SEN ; Начало формирования условия "START".
bcf Status,RP0 ; Переход в 0-й банк.
;....................................................
; Сюда, в случае необходимости, можно "врезать"
; "линейный" или "условно линейный кусок" программы.
;....................................................
btfss PIR1,SSPIF ; Формирование условия "START"
; завершено или нет?
goto $-1 ; Если нет, то ожидание.
; Если завершено, то программа
; исполняется далее.
;================================================================================
; Передача режимного байта.
;================================================================================
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 ; байта адреса.
;--->Возврат по стеку из ПП WR_I2C
;================================================================================
; Запись массива байтов в 24С64.
;================================================================================
8
; Стандартная процедура косвенной адресации.
;-------------------------------------------
movlw 5 ; Задание количества
movwf Byte ; записываемых байтов.
movlw Temp1 ; Сначала передается байт, "лежащий" в
movwf FSR ; Temp_1, а за ним, в порядке увеличения
SNOVA movf IndF,W ; числового значения адреса, и все остальные.
call WR_I2C ; Запись в 24C64 текущего байта данных.
;--->Возврат по стеку из ПП WR_I2C
incf FSR,F ; FSR + 1 = ...
decfsz Byte,F ; Записаны все байты данных или не все ?
goto SNOVA ; Если не все, то переход на запись
; следующего байта.
; Если все, то программа исполняется далее.
;================================================================================
; Формирование условия "STOP".
;================================================================================
bcf PIR1,SSPIF ; Сброс флага перерываний от модуля MSSP.

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


bsf SSPCon2,PEN ; Начало формирования условия "STOP".
bcf Status,RP0 ; Переход в 0-й банк.
;....................................................
; Сюда, в случае необходимости, можно "врезать"
; "линейный" или "условно линейный кусок" программы.
;....................................................
btfss PIR1,SSPIF ; Формирование условия "STOP"
; завершено или нет?
goto $-1 ; Если нет, то ожидание.
; Если завершено, то программа
; исполняется далее.
;------------------------------------
; "Закончен бал, погасли свечи".
;------------------------------------
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 ; после чего - возврат по стеку.
;********************************************************************************
end ; Конец программы.

9
В этой программе всего 55 слов.
А без учета 10-ти команд "загрузки" байтов данных в Temp1 … Temp5, команды goto $,
и того меньше.
Можно сделать и еще меньше, если использовать PIC18Fxx (минус "банковские"
переходы).
Иван так и поступил ("зер гут"!!!), но я пока "привязался" к PIC16F873A, а "разборки" с
PIC18Fxx будут устроены позднее (нужно быть последовательным).
Примечание: PIC18Fxx и "фантастишь" это одно и то же (управляемый стек, 2 вектора
прерываний и т.д.). Бог даст, доберусь и до них.
Ниже Вы видите блок – схему "вышележащей" программы:

Работа программы.
В начале программы, в регистры оперативной памяти общего назначения Temp1 …
Temp5, последовательно записываются числовые значения пяти байтов данных,
которые, в дальнейшем, нужно записать в память м/схемы 24С64.
Далее, производится инициализация (настройка) модуля MSSP.
А как же без этого?

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

movlw b'00101000' ; Включение модуля MSSP (SSPEN=1),


movwf SSPCon ; в режиме I2C-ведущего (SSPM3..SSPM0=1000).

Сразу нужно разобраться с настройками по умолчанию (см. окно SFR).


При работе модуля MSSP, задействуются выводы RC3 (такт) и RC4 (данные).
Их нужно настроить на работу "на вход".
Примечание: из-за непобедимого любопытства, я специально настраивал их на работу
"на выход" и получил "добросовестный Гитлер капут".
Так как, по умолчанию, все выводы портов настроены на работу "на вход", то и
направления работы выводов программно задавать не нужно.
По умолчанию, все модули (кроме TMR0) выключены.
Еще раз их выключать (программно) не требуется.
По этой же причине, не нужно запрещать прерывания (по умолчанию, они запрещены).
По умолчанию, все регистры SSP… приведены в "первозданное" ("неоплодотворенное")
состояние (кроме SSPBuf. В нем может лежать всяческая "абракадабра". Это "по
барабану", так как далее будет запись "по верху").
То есть, в них "лежат" нули, что соответствует сбросу "всего, что шевелится".
Вот от этого "первородного греха" и начинаются "песни с плясками" (так же, как и все
живое).
По поводу "банковских" переходов: я не буду акцентировать на них Ваше внимание (за
исключением одного случая, см. ниже).
Просто посмотрите в распечатку области оперативной памяти PIC16F873A (или в
"шапку" программы), и Вам станет ясно, откуда взялись эти переходы.
С учетом сказанного, инициализация модуля MSSP начинается с установки скорости
обмена.
В данном случае, выбрана частота 100 Кгц.
Далее, в соответствии с этим выбором, управление длительностью фронта
отключается.
Примечание: это "для порядка" (см. начало стр. 3).
После этого, модуль MSSP включается в режиме I2C-ведущего.
Вот и вся инициализация.
Далее, "моделируется" стандартная последовательность действий, определяемая
"I2C-правилам игры".
Она начинается с формирования условия "START".

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

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


bsf SSPCon2,SEN ; Начало формирования условия "START".
bcf Status,RP0 ; Переход в 0-й банк.
;....................................................
; Сюда, в случае необходимости, можно "врезать"
; "линейный" или "условно линейный кусок" программы.
;....................................................
btfss PIR1,SSPIF ; Формирование условия "START"
; завершено или нет?
goto $-1 ; Если нет, то ожидание.
; Если завершено, то программа
; исполняется далее.

11
В соответствии с "вышележащей" последовательностью действий, сначала сбрасывается
флаг SSPIF.
В данном случае, его можно и не сбрасывать, так как он сброшен по умолчанию, но в
тех случаях, когда происходит "закольцовка" на начало "стартовой" процедуры, сброс
флага SSPIF, перед началом формирования условия "START", нужен.
Процедура формирования стартового бита "запускается" установкой бита SEN в
единицу.
После этого отрабатывается классическая "плавающая" задержка, работающая с
флагом SSPIF.
По окончании формирования стартового бита, флаг SSPIF аппаратно поднимается, что
приводит к выходу рабочей точки программы из "плавающей" задержки.
Начинается передача байтов:

;================================================================================
; Передача режимного байта.
;================================================================================
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 ; байта адреса.
;--->Возврат по стеку из ПП WR_I2C

В соответствии с требованиями I2C-протокола, первым передается режимный байт.


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

;================================================================================
; Запись массива байтов в 24С64.
;================================================================================
; Стандартная процедура косвенной адресации.
;-------------------------------------------
movlw 5 ; Задание количества
movwf Byte ; записываемых байтов.
movlw Temp1 ; Сначала передается байт, "лежащий" в
movwf FSR ; Temp_1, а за ним, в порядке увеличения
SNOVA movf IndF,W ; числового значения адреса, и все остальные.
12
call WR_I2C ; Запись в 24C64 текущего байта данных.
;--->Возврат по стеку из ПП WR_I2C
incf FSR,F ; FSR + 1 = ...
decfsz Byte,F ; Записаны все байты данных или не все ?
goto SNOVA ; Если не все, то переход на запись
; следующего байта.
; Если все, то программа исполняется далее.

Используется стандартная процедура косвенной адресации, которая ранее применялась


много раз, и ничего нового в ней нет.
В данном случае, обрабатывается 5 байтов.
После окончания передачи всех пяти байтов данных, формируется условие "STOP":

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

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


bsf SSPCon2,PEN ; Начало формирования условия "STOP".
bcf Status,RP0 ; Переход в 0-й банк.
;....................................................
; Сюда, в случае необходимости, можно "врезать"
; "линейный" или "условно линейный кусок" программы.
;....................................................
btfss PIR1,SSPIF ; Формирование условия "STOP"
; завершено или нет?
goto $-1 ; Если нет, то ожидание.
; Если завершено, то программа
; исполняется далее.

При этом, имеет место быть полная аналогия с формированием условия "START".
Отличие только в том, что в единицу устанавливается не бит SEN, а бит PEN.
Следует учесть то, что эти биты устанавливаются программно, а сбрасываются
аппаратно.
То есть, программно сбрасывать биты SEN и PEN не нужно.
Модуль MSSP их автоматически сбросит и без Вашего участия.
Вот такой приятный "сервис".
У флага SSPIF все наоборот: он устанавливается аппаратно, а сбрасывается
программно.
Цикл передачи массива байтов закончен.
Теперь:
goto $ ; "Вечное, мертвое кольцо" (вместо него
; может быть продолжение программы).
после чего - "уход в вечное кольцо" (программа одноцикловая).

Теперь о ПП передачи байта и анализа отклика ведомого.


Уже из названия понятно, что в ней делается.

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

Подпрограмма начинается с копирования байта, предназначенного для передачи, из


аккумулятора, в регистр SSPBuf, что есть запись в регистр SSPBuf.
А раз это так, то "запускается аппаратный механизм" передачи байта данных (не
важно какой функциональности).
Для того чтобы не затягивать полный цикл программы, флаг SSPIF лучше сбросить не
до начала цикла передачи байта (до команды movwf SSPBuf), а сразу же после его
начала (после команды movwf SSPBuf).
Далее отрабатывается стандартная "плавающая" задержка, при помощи которой
"пережидается" цикл передачи байта.
Можно не беспокоиться. Модуль MSSP передаст байт "в лучшем виде".
Мало того, он автоматически перестроит вывод SDA на работу "на вход" и примет
уровень сигнала АСК, который выдает 24C64 после приема им текущего байта данных.
В конечном итоге, этот уровень запишется в бит ACKSTAT ("блюдечко с голубой
каемочкой". Остается только в рот положить).
Причем, эта запись и поднятие флага SSPIF происходят одновременно.
Следовательно, анализ отклика можно производить сразу же после отработки
"плавающей" задержки, что и имеет место быть.
Далее производится простейший анализ состояния бита ACKSTAT с ветвлением на 2
сценария.

1. ACKSTAT = 0 (нулевой уровень сигнала АСК).


В этом случае считается, что байт принят ведомым без ошибок и происходит возврат
на начало цикла передачи следующего байта (return).
Но вернуться нужно не с 1-м, а с 0-м банком, ведь анализ происходит в 1-м банке, а
войти в ПП WR_I2C нужно с 0-м банком.
Поэтому, перед командой return, исполняется команда перехода в 0-й банк.
Пояснение: в PIC16F873A, регистры общего назначения 0-го банка не отображаются в
1-м банке (регистры общего назначения 0-го банка отображаются в 2-м банке, а
регистры общего назначения 1-го банка отображаются в 3-м банке).
Так как регистр Byte "прописан" в 0-м банке, то возвращаться в процедуру косвенной
адресации нужно с 0-м банком.
Можно было бы "похимичить" с банками, но я этого делать не стал.
Пусть будет так, как привычно.

2. ACKSTAT = 1 (единичный уровень сигнала АСК).


В этом случае считается, что байт принят ведомым с ошибкой и происходит повторная
передача текущего байта (goto POVTOR).
Так как этот переход происходит с 1-м банком, а регистры SSPBuf и PIR1 "лежат" в
0-м банке, то первой командой повторного цикла передачи байта должна быть команда
перехода в 0-й банк.
Это Вы и видите.
Пояснение: отсутствие подтверждения, со стороны ведомого, о принятии им байта
(любой функциональности), однозначно свидетельствует о том, что счетчик адреса
24С64 не автоинкрементировался.
Это означает то, что можно произвести повторную запись ранее переданного байта в
текущую ячейку памяти, "по верху" того "брака", который в нее записался.
Причем, повторная запись может производиться не один, а несколько раз.
14
Эта "свистопляска" будет продолжаться до безошибочного приема байта ведомым
(ACKSTAT = 0).
Как только это произойдет, будет отработан 1-й сценарий.

Убрав команду goto $, можно продолжить программу.

Теперь обратите внимание на комментарии, выделенные серым цветом.


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

Итак, модуль MSSP работает по принципу "Вы меня только грамотно запустите в
работу, а я ее сделаю в лучшем виде (без Вас), да еще и отчитаюсь о
результате".
Короче, мечта конструктора …
Но при одном условии: конструктор должен быть грамотным.
То есть, он должен четко представлять себе последствия включения/выключения того
или иного "рубильника".

IcProg может работать и с PIC16F873A, и с 24С64 (JDM Programmer) .


При работе с PIC16F873A, в "Настройках программатора", в опции "Инверсия
данных вывода" должна стоять галочка.
При работе с 24С64, эту галочку нужно убрать.
Изначально, в IcProg, в первых пяти ячейках 24С64, желательно "настучать", например,
нули, а затем произвести запись этих нулей.
Если же будут производиться "эксперименты", то это "обнуление" желательно делать
перед каждым включением питания устройства (перед каждой записью).
После этого, Вы будете застрахованы от ошибочной оценки полученного результата.
Такой способ контроля не совсем удобен, но позволяет максимально упростить
программу и увеличить "скорость въезда в модуль".

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

15
16

Оценить