В HTML      В PDF
микроэлектроника, микросхема, транзистор, диод, микроконтроллер, память, msp430, Atmel, Maxim, LCD, hd44780, t6963, sed1335, avr, mega128
Предприятия Компоненты Документация Применения Статьи Новости

 
Пересюхтюмя


13-я Международная выставка электронных компонентов и комплектующих для электронной промышленности





Выставка Передовые Технологии Автоматизации





Главная страница > Применение > Микроконтроллеров > MSP430
Пересюхтюмя


13-я Международная выставка электронных компонентов и комплектующих для электронной промышленности





Выставка Передовые Технологии Автоматизации


Реализация шины SMBus на базе микроконтроллера MSP430

Краткое содержание

Данный пример применения описывает программную реализацию шины системного управления (system management bus (SMBus)) на базе микроконтроллера MSP430. Рассмотрены протоколы ведущего (master) устройства, базирующегося на прерываниях ведомого (slave), а также примеры использования ведущего устройства. Шина SMBus является подвидом шины 2C и широко используется в смарт-батареях (smart batteries) и других системных устройствах.

1 Введение

SMbus это двухпроводной синхронный последовательный протокол, являющийся производным от I2C. Так же, как и 2C, он использует линии последовательного тактирования (SCL) и данных (SDA). Для исключения неопределённого состояния на линии используются подтягивающие (pullup) резисторы или источники тока, а устройства, подключенные к шине должны иметь выходы типа «открытый коллектор» либо «открытый сток». Это соответствует монтажному «И» всех устройств, что означает, что каждое из устройств может либо перевести шину в состояние лог. «0», либо освободить её. Так как подключённые к шине устройства могут быть запитаны от различных напряжений, они не должны переводить линию в состояние лог. «1».

Все устройства разделяются на ведущие (master) и ведомые (slave). Ведущее устройство может инициировать передачу и формирует тактовый сигнал. Ведомое принимает либо передаёт данные, но при этом процесс передачи инициируется ведущим. Устройства могут иметь как признаки ведущего и ведомого одновременно, так и быть исключительно одним либо другим. Например, ведомое устройство может в критических случаях становиться ведущим и передавать системе сообщения о неисправности. Алгоритм такого поведения целиком определяется конкретной областью применения.

Каждое устройство на шине имеет уникальный 7-битный адрес. Это позволяет подключать к линии до 128 устройств, однако некоторые адреса являются зарезервированными. Различные коммерчески доступные устройства имеют адреса, присвоенные координационным комитетом SMBus.

При приёме и передаче данных используются семь различных протоколов. Это «Быстрая команда» (Quick Command), «Отправить байт» (Send Byte), «Принять байт» (Receive Byte), «Записать Слово/Байт» (Write Byte/Word), «Прочитать Слово/Байт» (Read Byte/Word), «Запрос состояния» (Process Call), и «Чтение/запись Блока» (Block Read/Write). Каждый протокол имеет собственный конкретный набор действий, но общая схема схожа для всех протоколов.

Передача всегда начинается с символа «Старт» (S). Этот символ передаётся переводом обеих линий в состояние лог. «1», последующим переводом линии SDA в состояние лог. «0» и, наконец, выставлением лог. «0» на шине SCL. После передачи стартовой последовательности, начинается передача 8-ми блоков, завершающаяся подтверждением (ACK). Подтверждение передаётся ведомым устройством путём перевода линии SDA в состояние лог. «0» во время передачи ведущим сигнала SCL. Если линия SDA не была переведена в такое состояние за время импульса на шине SCL, это состояние называется неподтверждением (NACK). Первый 8-битный блок является 7-битным адресом ведомого устройства вкупе с битом, определяющим направление передачи во всех протоколах, за исключением «Быстрой команды». В последнем же данный бит собственно является командой. После передачи адреса и направления, ведущий ожидает подтверждения от ведомого. При этом он формирует одиночный импульс на линии SCL и контролирует перевод ведомым в это время линии SDA в состояние лог. нуля. Если подтверждение не получено, ведущее устройство прекращает передачу и повторяет её позднее. Эта операция также может использоваться для определения присутствия ведомого на шине. После получения подтверждения, передаётся либо получается очередной блок из 8-ми бит, либо передаётся символ останова (P). Этот символ формируется переводом обеих линий в состояние лог. «0», последующим переводом линии SCL в состояние лог. «1» и завершается переводом в лог. «1» линии SDA. Остальные 8-битные блоки могут быть данными, командами либо следующей комбинацией адреса и бита чтения/записи. Точный формат каждого из протоколов можно найти в документе System Management Bus specification на сайте . Ввиду того, что на шине используется подключение устройств по принципу «монтажное «И»», она обладает механизмом арбитража. Если более одного ведущего устройства пытаются передавать данные, первый из них, «отпустивший» шину во время того, как оставшийся удерживает её в состоянии лог. «0» должен отдать арбитраж. Чтобы обеспечить эффективность такого метода, каждое ведущее устройство должно проверять состояние шины каждый раз после перевода её в состояние лог. «1». Если после этого шина удерживается в состоянии лог. «0», ведущее устройство должно прекратить передачу и повторить попытку позднее. В результате такого решения системы арбитража, устройства с меньшими адресами имеют приоритет над устройствами со старшими адресами. Если два ведущих пытаются начать передачу одновременно, тот из них, который передаёт старший адрес, первым освободит линию и потеряет, таким образом, приоритет.

Рабочими частотами шины являются 10 кГц и 100 кГц. Это аналогично шине 2C, за исключением того, что 2C не имеет ограничения скорости снизу, при этом устройства могут занимать шину на неограниченное время. SMBus имеет более жёсткие ограничения, ограничивая минимальную скорость. Несмотря на это, ведомые устройства не обязаны работать с той же частотой, что и ведущие. Единственным ограничением является минимальная скорость их работы в 10 кГц. Возможность работы с разной скоростью реализована следующим образом: если ведомому устройству требуется дополнительное время для завершения операции, оно принуждает ведущего к ожиданию удержанием линии SCL в состоянии лог. «0». Это называется «удлинением тактового сигнала» (clock-low extending). Ведущее устройство должно дождаться, пока ведомое «отпустит» линию SCL, но , если это займёт больше времени, чем разрешено спецификацией, произойдёт тайм-аут. Этим обеспечивается минимальная скорость шины. Дополнительную информацию по протоколу SMBus можно найти на форуме Smart Battery System Implementers Forum (SBS IF). Комитет SBS IF образован представителями фирм Benchmarq Microelectronics Inc., Duracell Inc., Energizer Power Systems, Intel Corporation, Linear Technology Corporation, Maxim Integrated Products, Mitsubishi Electric Corporation, National Semiconductor Corporation, Toshiba Battery Co., и Varta Batterie AG. Комитетом опубликована спецификация SMBus, доступная для скачивания на сайте в формате pdf.

2 Аппаратная часть

На рис. 1 приведен пример подключения шины SMBus. В этом случае MSP430 подключен к смарт-батарее. Батарея питает шину и MSP430, но это не является обязательным, необходимым условием является лишь общая «земля». Подтягивающие (pull up) резисторы обозначены как RP. Для уменьшения потребляемого тока, значения RP выбраны максимально возможными в рамках требований спецификации. Существуют также специальные драйвера шины SMBus, используемые вместо подтягивающих резисторов. Такие устройства обеспечивают максимальный ток на фронте и минимальный при низком уровне на шине.


Рис1. Пример организации шины SMBus

Примечание: Неиспользованный вывод T это термистор. Он используется в блоках Li-Ion батарей для аварийных измерений в случае неисправности модуля батареи или шины SMBus.

3 Реализация ведущего устройства шины SMBus

Программа ведущего устройства шины SMBus для MSP430 реализует все существующие типы протоколов. Для экономии регистров, параметры передаются через стек. Максимальная глубина стека 40 байт. Память вне стека не затрагивается, кроме случая операций над блоками. Во время передачи блока его начало передаётся как параметр (блок растёт в сторону верхних адресов памяти). Во время записи блока его размер известен до начала передачи, во время приёма блока его размер передаётся ведомым устройством. При этом следует соблюдать осторожность, чтобы данные из блока не затёрли программную или оперативную память.

Программа состоит из двух основных частей: подпрограмм верхнего уровня и подпрограмм нижнего уровня. Низкоуровневые подпрограммы обрабатывают сдвиг бит, временнЫе характеристики и работу с портами ввода-вывода. Протоколы SMBus, по существу, состоят из нескольких стандартных блоков, которые вызываются и повторяются в определенном порядке. Эти стандартные блоки обрабатываются подпрограммами нижнего уровня. Подпрограммы верхнего уровня обеспечивают пользовательский интерфейс и сохраняют регистры. На каждый протокол приходится одна такая подпрограмма, в них устанавливаются параметры, а затем вызываются подпрограммы нижнего уровня. Для обеспечения требования протокола SMBus к выходам («открытый коллектор»), выводы процессора переключаются со входа на выход и наоборот. В выходных защёлках портов всегда присутствует лог. «0». Это означает, что MSP430 может «освободить» линию переключением вывода на вход, либо «занять» её (т.е. выставить там лог. «0») путём переключения вывода на выход. Выбор требуемых выводов осуществляется «привязкой» их в начале программы к конкретным линиям SDA, SCL и DNC. SDA и SCL соответствуют линиям данных и тактирования шины SMBus. DNC является одновременно линиями SCL и SDA. Соответствующий порт выбирается назначением OUT, DIR и IN. В зависимости от конкретного применения, могут использоваться не все протоколы. Ненужные подпрограммы могут быть «закомментированы», что уменьшит размер кода. Удаление подпрограмм высокого уровня является очевидным, при этом возможно также удаление некоторых неиспользуемых подпрограмм низкого уровня.

Так как SMBus поддерживает несколько ведущих устройств на шине (multimaster) и «горячее включение» (hot-plug), это приводит к появлению ошибок. Их причинами являются занятость шины, отсутствие ведомого устройства, конфликты между несколькими ведущими устройствами и помехи на шине. Программа включает обработку ошибок и флаг ошибки. При обнаружении ошибки передача прекращается, программа выставляет флаг ошибки и возвращается из подпрограммы верхнего уровня. Пользовательская программа должна проверять данный флаг для определения успешного (возвращает 1) или ошибочного (возвращает 0) завершения. Обработка события ошибки осуществляется пользовательской программой.

Основная программа включает в себя подпрограммы верхнего и нижнего уровней и располагается отдельно от пользовательской программы. Место, где должна располагаться пользовательская программа оставлено свободным. Для передачи данных по шине SMBus, просто вызывается соответствующая подпрограмма верхнего уровня.

Примеры передачи параметров приведены в комментариях к каждой подпрограмме. Исходные коды приведены в приложении A. Также в приложениях приводятся демонстрационные программы, иллюстрирующие различные протоколы и примеры работы с смарт-батареей.

4 Примеры реализации программы ведущего устройства шины SMBus

4.1 Поиск устройств на шине

Первый пример довольно прост. В нём производится поиск устройств, присутствующих на шине и отображение адреса последнего найденного устройства. Это весьма удобно во время проверки соединений шины. Первоначально пример был написан для поиска адресов устройств, он наглядно демонстрирует возможность уменьшения размера кода при помощи удаления неиспользуемых подпрограмм.

Ввиду простоты примера, была удалена значительная часть кода. Оставшийся код можно запускать из-под программы монитора отладочного модуля MSP430x33x (EVK part number MSP-EVK430x330).

4.2 Чтение данных смарт-батареи

Этот пример значительно объёмнее первого. В нём используются протоколы «Чтение слова», «Запись слова» и «Чтение блока» для связи со смарт-батареей. В примере считываются температура, напряжение, производитель, химическая разновидность и ёмкость батареи.

Также используется запись значения в регистр «Предупреждение об оставшейся ёмкости» (RemainingCapacityAlarm), записанное значение проверяется. Эти операции производятся циклически, результат отображается на ЖКИ. Пример демонстрирует использование более сложных протоколов и процесс обработки возвращаемых данных. В данной конфигурации программа протоколов SMBus запускается из EPROM отладочного модуля MSP430x33x (EVK part number MSP-EVK430x330), а пользовательская программа запускается из монитора этого модуля.

5 Реализация ведомого устройства шины SMBus

Эта программа представляет пример реализации ведомого устройства шины SMBus и построена на базе прерываний. Назначения при помощи оператора. equ в начале программы позволяют выбрать адрес ведомого устройства, выводы и порты. В программе реализован протокол «Отправка байта» (что для ведомого устройства означает передачу байта к нему от ведущего). В промежутке между прерываниями ведомое устройство может находиться в режиме пониженного потребления либо выполнять другие задачи. Так как прерывание происходит каждый раз при переходе линии SDA из состояния лог. «1» в лог. «0», ведомое устройство при загруженности шины проводит значительную часть времени в подпрограмме обработки прерываний.

Чтобы исключить контроль шины ведомым устройством во время работы с другими ведомыми могут быть использованы внешние элементы, контролирующие шину и формирующие прерывания только при совпадении адреса ведомого устройства. Ещё одним недостатком использования прерываний без дополнительных внешних устройств является время обработки прерывания. Так как оно составляет несколько тактов, при этом существует вероятность пропуска стартовой последовательности. При реализации поллинга вероятность пропустить стартовую посылку снижается, но процессор постоянно занят отслеживанием состояния шины. Выбор оптимального решения зависит от конкретной реализации. Вариант с прерываниями позволяет процессору обслуживать другие задачи во время неактивного состояния шины, но при этом есть вероятность пропустить первую попытку установления связи. Вариант с поллингом не оставляет процессору возможности обрабатывать другие задачи вне зависимости от состояния шины. Потребление также при этом возрастает, так как процессор не может быть переведен в режим пониженного энергопотребления во время неактивного состояния шины.

На базе данного протокола возможна реализация остальных. В нашем примере обрабатываются стартовые и стоповые последовательности, приём 7-битных блоков адреса и 8-битных блоков данных / команд. Использование этих процедур в требуемом порядке позволяет реализовать некоторые другие протоколы.

Регистры не сохраняются в стеке с целью обеспечения требований спецификации в области наиболее быстрой стартовой последовательности. Время между переходом линий SDA и SCL в состояние лог. «0» может составлять всего 4 мс. Если известно, что ведущее устройство выдаёт сигналы с большей длительностью, можно сохранять регистры в стеке в начале процедуры, но это может привести к пропуску стартовой посылки при работе с более быстрым ведущим устройством.

6 Заключение

Необходимость увеличения времени жизни батарей в переносных устройствах привела к разработке батарей со сложным химическим составом и повышению требований к технологиям мониторинга. Шина SMBus предоставляет удобный и чёткий интерфейс для мониторинга смарт-батарей, а сверхнизкое потребление микроконтроллера MSP430 делает его незаменимым для таких систем.

Приложение A Программа ведущего устройства шины SMBus

;*****************************************************************************************
; Программа ведущего устройства шины SMBus, параметры передаются через стек
;*****************************************************************************************
RAM_orig       .set    00240h                ; Стартовый адрес в ОЗУ
SP_orig        .set    005DEh                ; Указатель стека
EPROM          .set    08850h                ; Размещение EPROM
;––– Определения управляющих регистров
WDTCTL         .equ    0120h
WDTHold        .equ    80h
WDT_wrkey      .equ    05A00h
;PORT 0
P0IE           .equ    015h
P0DIR          .equ    012h
P0IN           .equ    010h
P0OUT          .equ    011h
; port 2
P2IN           .equ    028h
P2OUT          .equ    029h
P2IE           .equ    02Dh
P2SEL          .equ    02Eh
P2DIR          .equ    02Ah
SDA            .equ    020h
SCL            .equ    080h
DNC            .equ    0A0h
OUT            .equ    P2OU
TDIR           .equ    P2DIR
IN             .equ    P2IN
LCD1           .equ    031h
LCDM           .equ    030h
IE1            .equ    0h
IE2            .equ    01h
IFG1           .equ    02h
IFG2           .equ    03h
block          .equ    0550h
alcd           .equ    0B500h           ; Размещение таблицы символов 
                                        ; ASCII для ЖКИ
;*****************************************************************************************
; Reset : инициализация процессора
;*****************************************************************************************
.sect   ”MAIN”,RAM_orig
RESET
        MOV    #SP_orig,SP                ; Инициализация указателя стека
;*******************************************************************************
; Начало пользовательской программы
;*****************************************************************************************
; Здесь должна быть расположена пользовательская программа
;*****************************************************************************************
; Завершение пользовательской программы 
;*****************************************************************************************
.sect    ”smbus”, EPROM
;*****************************************************************************************
; Подпрограммы верхнего уровня, п/п нижнего уровня вызываются индивидуально 
; для реализации различных протоколов 
;*****************************************************************************************
; Протокол «Быстрая команда» 1
; ==========================================================================
; Влияние на регистры: нет
; Влияние на память: стек, максимум 40 байт
; ––––––––––––––––––––––––––-––––––––––––––––––––––––––-––––––––––––––––––––––––
; Описание     Шаг                     Направление
; ––––––––––––––––––––––––––––––––––––––––––––––––––––-–––––––––––––––––––––––––
;         старт (start)                 из
;         адрес(address)                из
;         чтение/запись(R/W)            из
;         подтверждение(acknowledge)    в   ?
;         стоп (stop)                   из
;
; Параметры в стеке
; ––––––––––––––––––––
; флаг ошибки    error_flag    младшая область памяти    low mem
; не используется    unused
; не используется    unused
; не используется    unused
; адрес        address    старшая область памяти    high mem
;
; Пример использования 
; ––––––––––––––
;       PUSH    #00h          ; место для кода ошибки
;       PUSH    #00Bh         ; поместить адрес в стек
;       SUB     #06h, SP      ; остальные параметры не используются
;       CALL    #qcp
;       ADD     #08h, SP      ; вычесть объём параметров
;       POP     R9            ; читать из стека код ошибки
;       CMP     #00h, R9
;       JZ      error         ; ошибочное завершение – вызов обработчика ошибок
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
qcp
        PUSH     SR
        PUSH     R7
        PUSH     R8
        PUSH     R9
        PUSH     R14
        PUSH     R15
        PUSH     R10
        PUSH     R11
        PUSH     R12
        PUSH     R13
        MOV.B 28(SP), R7     ; получить адрес из стека
        CALL    #sbit         ; отправить стартовую посылку и адрес
        ;CALL    #sendone     ; отправить «1» или
        CALL    #sendzero     ; отправить «0»
        CALL    #ack         ; ждём подтверждения (ACK)
        CALL    #pbit         ; отправить стоповую посылку
        MOV.B #01h, 30(SP) ; возвращает «1» при успешном завершении
        POP    R13
        POP    R12
        POP    R11
        POP    R10
        POP    R15
        POP    R14
        POP    R9
        POP    R8
        POP    R7
        POP    SR
        RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Протокол «Отправить байт» 2
; ==========================================================================
; Влияние на регистры: нет
; Влияние на память: стек, максимум 40 байт
; ––––––––––––––––––––––––––-––––––––––––––––––––––––––-––––––––––––––––––––––––
; Описание     Шаг                     Направление
; ––––––––––––––––––––––––––––––––––––––––––––––––––––-–––––––––––––––––––––––––
;         старт (start)                 из
;        адрес(address)             из
;        чтение/запись(R/W)             из
;        подтверждение(acknowledge)     в   ?
;         команда (command)            из
;        подтверждение(acknowledge)     в   ?
;         стоп (stop)                 из
;
; Параметры в стеке
; ––––––––––––––––––––
; флаг ошибки    error_flag    младшая область памяти    low mem
; не используется    unused
; не используется    unused
; данные         data
; адрес        address    старшая область памяти    high mem
;
; Пример использования 
; ––––––––––––––
;       PUSH    #00h        ; место для кода ошибки
;       PUSH    #00Bh        ; поместить адрес в стек
;       PUSH    #055h         ; отправляемые данные 
;       SUB    #04h, SP     ; остальные параметры не используются
;       CALL #sbp
;       ADD    #08h, SP    ; вычесть объём параметров
;       POP    R9         ; читать из стека код ошибки
;       CMP    #00h, R9
;       JZ    error         ; ошибочное завершение – вызов обработчика ошибок
sbp
        PUSH    SR
        PUSH    R7
        PUSH    R8
        PUSH    R9
        PUSH    R14
        PUSH    R15
        PUSH    R10
        PUSH    R11
        PUSH    R12
        PUSH    R13
        MOV.B 28(SP), R7         ; получить адрес из стека
        MOV.B 26(SP), R8         ; получить данные из стека
        CALL    #sbit             ; отправить стартовую посылку и адрес
        CALL    #sendzero         ; отправить «0» для записи
        CALL    #ack             ; ждём подтверждения (ACK)
        CALL    #sbyte         ; отправить байт команды
        CALL    #ack             ; ждём подтверждения (ACK)
        CALL    #pbit             ; отправить стоповую посылку
        MOV.B #01h, 30(SP)     ; возвращает «1» при успешном завершении
        POP    R13
        POP    R12
        POP    R11
        POP    R10
        POP    R15
        POP    R14
        POP    R9
        POP    R8
        POP    R7
        POP    SR
        RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Протокол «Принять байт» 3
; ==========================================================================
; Влияние на регистры: нет
; Влияние на память: стек, максимум 40 байт
; ––––––––––––––––––––––––––-––––––––––––––––––––––––––-––––––––––––––––––––––––
; Описание     Шаг                     Направление
; ––––––––––––––––––––––––––––––––––––––––––––––––––––-–––––––––––––––––––––––––
;         старт (start)                 из
;        адрес(address)             из
;        чтение/запись(R/W)             из
;        подтверждение(acknowledge)     в   ?
;         данные (data)                в   ?
;        неподтверждение(NACK)         из
;         стоп (stop)                 из
;
; Параметры в стеке
; ––––––––––––––––––––
; флаг ошибки    error_flag    младшая область памяти    low mem
; данные         data
; не используется    unused
; команда         command
; адрес        address    старшая область памяти    high mem
; –––––––––––––––––
; Пример использования 
; ––––––––––––––
;       PUSH    #00h         ; место для кода ошибки
;       PUSH    #00Bh        ; поместить адрес в стек
;       PUSH    #08h         ; код команды
;       SUB     #04h, SP     ; зарезервировать место под принимаемые данные
;       CALL    #rcbp 
;       POP     R8           ; переместить данные в R8
;       ADD     #06h, SP     ; вычесть объём параметров
;       POP     R9           ; читать из стека код ошибки
;       CMP     #00h, R9
;       JZ      error        ; ошибочное завершение – вызов обработчика ошибок
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
rbp
        PUSH    SR
        PUSH    R7
        PUSH    R8
        PUSH    R9
        PUSH    R14
        PUSH    R15
        PUSH    R10
        PUSH    R11
        PUSH    R12
        PUSH    R13
        MOV.B 26(SP), R8     ; параметр команды
        MOV.B 28(SP), R7     ; параметр адреса
        CALL    #sbit        ; отправить стартовую посылку и адрес
        CALL    #sendzero    ; отправить «0» для записи
        CALL    #ack         ; ждём подтверждения (ACK)
        CALL    #sbyte       ; отправить код команды
        CALL    #ack         ; ждём подтверждения (ACK)
        CALL    #rsbit       ; отправить повторяющиеся стартовую посылку и адрес
        CALL    #sendone     ; отправить «1» для чтения
        CALL    #ack         ; ждём подтверждения (ACK)
        CALL    #rbyte         ; принять байт данных
        CALL    #nack         ; отправить неподтверждение (NACK)
        CALL    #pbit         ; отправить стоповую посылку
        MOV.B R14, 22(SP)     ; копировать байт данных в стек
        MOV.B #01h, 30(SP) ; возвращает «1» при успешном завершении
        POP    R13
        POP    R12
        POP    R11
        POP    R10
        POP    R15
        POP    R14
        POP    R9
        POP    R8
        POP    R7
        POP    SR
        RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Протокол «Принять слово» 7
; ==========================================================================
; Влияние на регистры: нет
; Влияние на память: стек, максимум 40 байт
; ––––––––––––––––––––––––––-––––––––––––––––––––––––––-––––––––––––––––––––––––
; Описание     Шаг                     Направление
; ––––––––––––––––––––––––––––––––––––––––––––––––––––-–––––––––––––––––––––––––
;         старт (start)                 из
;        адрес(address)             из
;        чтение/запись(R/W)             из
;        подтверждение(acknowledge)     в   ?
;        команда (command)            из
;        подтверждение(acknowledge)     в   ?
;         старт (start)                 из
;        адрес(address)             из
;        чтение/запись(R/W)             из
;        подтверждение(acknowledge)     в   ?
;         данные (data)                в   ?
;        подтверждение(acknowledge)     в   ?
;         данные (data)                в   ?
;        подтверждение(acknowledge)     в   ?
;         стоп (stop)                 из

; Параметры в стеке
; ––––––––––––––––––––
; флаг ошибки        error_flag    младшая область памяти    low mem
; младший байт данных     low data byte
; старший байт данных     high data byte
; команда             command
; адрес            address    старшая область памяти    high mem

; –––––––––––––––––
; Пример использования 
; ––––––––––––––
;       PUSH    #00h        ; место для кода ошибки
;       PUSH    #00Bh        ; поместить адрес в стек
;       PUSH    #008h        ; код команды “температура батареи”
;       PUSH    #00h        ; зарезервировать байт под принимаемые данные
;       PUSH    #00h        ; зарезервировать байт под принимаемые данные
;       CALL    #rwp
;       POP     R10         ; переместить данные в R10
;       POP     R11         ; переместить данные в R11
;       ADD     #04h, SP    ; освободить место, занимаемое командой и адресом
;       POP     R9         ; читать из стека код ошибки
;       CMP     #00h, R9
;       JZ      error         ; ошибочное завершение – вызов обработчика ошибок
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
rwp
        PUSH    SR
        PUSH    R7
        PUSH    R8
        PUSH    R9
        PUSH    R14
        PUSH    R15
        PUSH    R10
        PUSH    R11
        PUSH    R12
        PUSH    R13
        MOV.B 26(SP), R8     ; параметр команды
        MOV.B 28(SP), R7     ; параметр адреса
        CALL    #sbit         ; отправить стартовую посылку и адрес
        CALL    #sendzero     ; отправить «0» для записи
        CALL    #ack         ; ждём подтверждения (ACK)
        CALL    #sbyte     ; отправить код команды
        CALL    #ack         ; ждём подтверждения (ACK)
        CALL    #rsbit         ; отправить повторяющиеся стартовую посылку и адрес
        CALL    #sendone     ; отправить «1» для чтения
        CALL    #ack         ; ждём подтверждения (ACK)
        CALL    #rbyte         ; принять младший байт данных
        MOV.B R14, 22(SP)     ; сохранить младший байт данных в стеке
        CALL    #sack         ; ждём подтверждения (ACK)
        CALL    #rbyte         ; принять старший байт данных
        CALL    #nack         ; отправить неподтверждение (NACK)
        CALL    #pbit         ; отправить стоповую посылку
        MOV.B R14, 24(SP)     ; сохранить старший байт данных в стеке
        MOV.B #01h, 30(SP) ; возвращает «1» при успешном завершении
        POP    R13
        POP    R12
        POP    R11
        POP    R10
        POP    R15
        POP    R14    
        POP    R9
        POP    R8
        POP    R7
        POP    SR
        RET

; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Протокол «Запись блока» 8
; ==========================================================================
; Влияние на регистры: нет
; Влияние на память: стек, максимум 40 байт, блок памяти
; Описание     Шаг                     Направление
; ––––––––––––––––––––––––––––––––––––––––––––––––––––-–––––––––––––––––––––––––
;        старт (start)                 из
;        адрес(address)             из
;        чтение/запись(R/W)             из
;        подтверждение(acknowledge)     в   ?
;        команда (command)            из
;        подтверждение(acknowledge)     в   ?
;        счётчик байт (byte count)        из
;        подтверждение(acknowledge)     в   ?
;        данные (data)                из
;        подтверждение(acknowledge)     в   ?
;
;        данные (data)                в   ?
;        подтверждение(acknowledge)     в   ?
;
;        данные и ACK повторяются n раз    
;        стоп (stop)                 из

; Параметры в стеке
; ––––––––––––––––––––
; флаг ошибки        error_flag    младшая область памяти    low mem
; счётчик байт        byte count
; указатель блока        block pointer
; команда             command
; адрес            address    старшая область памяти    high mem
; –––––––––––––––––
; Пример использования 
; ––––––––––––––
;       PUSH    #00h        ; место для кода ошибки
;       PUSH    #00Bh        ; поместить адрес в стек
;       PUSH    #0020h    ; код команды “температура батареи”
;       PUSH    #00550h     ; указатель на начало блока
;       PUSH    #00h        ; зарезервировать байт под счётчик 
;       CALL    #blkw
;       POP     R10         ; переместить данные в R10
;       ADD     #06h, SP    
;       POP     R9         ; читать из стека код ошибки
;       CMP     #00h, R9
;       JZ      error         ; ошибочное завершение – вызов обработчика ошибок
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
blkw
        PUSH    SR
        PUSH    R7
        PUSH    R8
        PUSH    R9
        PUSH    R14
        PUSH    R15
        PUSH    R10
        PUSH    R11
        PUSH    R12
        PUSH    R13
        MOV.B 26(SP), R8     ; параметр команды
        MOV.B 28(SP), R7     ; параметр адреса
        MOV 24(SP), R9     ; стартовый адрес блока
        MOV.B #00h, R15     ; циклический байтовый счётчик
        CALL    #sbit         ; отправить стартовую посылку и адрес
        CALL    #sendzero     ; отправить «0» для записи
        CALL    #ack         ; ждём подтверждения (ACK)
        CALL    #sbyte     ; отправить код команды
        CALL    #ack         ; ждём подтверждения (ACK)
        MOV.B 22(SP), R8     ; копировать счётчик байт
        CALL    #sbyte     ; отправить счётчик байт
        CALL    #ack         ; ждём подтверждения (ACK)
blk_rep MOV.B 0(R9), R8     ; передать данные из блока
        CALL    #sbyte     ; отправить байт данных
        CALL    #ack         ; ждём подтверждения (ACK)
        INC    R15         ; инкремент счётчика положения блока
        INC    R9         ; инкремент указателя блока
        CMP    22(SP), R15     ; проверка завершения данных
        JNZ    blk_rep     ; повтор до завершения
        CALL    #pbit        ; отправить стоповую посылку
        MOV.B #01h, 30(SP) ; возвращает «1» при успешном завершении
        POP    R13
        POP    R12
        POP    R11    
        POP    R10
        POP    R15
        POP    R14
        POP    R9
        POP    R8
        POP    R7
        POP    SR
        RET

; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Протокол «Чтение блока» 9
; ==========================================================================
; Влияние на регистры: нет
; Влияние на память: стек, максимум 40 байт, блок памяти
; Описание     Шаг                     Направление
; ––––––––––––––––––––––––––––––––––––––––––––––––––––-–––––––––––––––––––––––––
;        старт (start)                 из
;        адрес(address)             из
;        запись(W)                 из
;        подтверждение(acknowledge)     в   ?
;        команда (command)            из
;        подтверждение(acknowledge)     в   ?
;        старт (start)                 из
;        адрес(address)             из
;        чтение(R)                 из
;        подтверждение(acknowledge)     в   ?
;        счётчик байт (byte count)        в   ?
;        подтверждение(acknowledge)     из
;        данные (data)                в   ?
;        подтверждение(acknowledge)     из
;
;        данные и ACK повторяются n раз    
;        неподтверждение(NACK)         из
;        стоп (stop)                 из
; Параметры в стеке
; ––––––––––––––––––––
; флаг ошибки        error_flag    младшая область памяти    low mem
; счётчик байт        byte count
; указатель блока        block pointer
; команда             command
; адрес            address    старшая область памяти    high mem
; –––––––––––––––––
; Пример использования 
; ––––––––––––––
;       PUSH    #00h        ; место для кода ошибки
;       PUSH    #00Bh        ; поместить адрес в стек
;       PUSH    #0020h    ; код команды “температура батареи”
;       PUSH    #00550h     ; указатель на начало блока
;       PUSH    #00h        ; зарезервировать байт под счётчик 
;       CALL    #blkr
;       POP     R10         ; переместить счётчик  в R10
;       ADD     #06h, SP    
;       POP     R9         ; читать из стека код ошибки
;       CMP     #00h, R9
;       JZ      error         ; ошибочное завершение – вызов обработчика ошибок
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
blkr
        PUSH    SR
        PUSH    R7
        PUSH    R8
        PUSH    R9
        PUSH    R14
        PUSH    R15    
        PUSH    R10
        PUSH    R11
        PUSH    R12
        PUSH    R13
        MOV.B #00h, R15     ; циклический байтовый счётчик
        MOV.B 26(SP), R8     ; параметр команды
        MOV.B 28(SP), R7     ; параметр адреса
        MOV 24(SP), R9     ; стартовый адрес блока
        CALL    #sbit         ; отправить стартовую посылку и адрес
        CALL    #sendzero    ; отправить «0» для записи
        CALL    #ack         ; ждём подтверждения (ACK)
        CALL    #sbyte     ; отправить код команды
        CALL    #ack         ; ждём подтверждения (ACK)
        CALL    #rsbit         ; отправить повторяющиеся стартовую посылку и адрес
        CALL    #sendone     ; отправить «1» для чтения
        CALL    #ack         ; ждём подтверждения (ACK)
        CALL    #rbyte
        MOV.B R14, 22(SP)    ; поместить счётчик в стек
        CALL    #sack         ; отправить подтверждение (ACK)
        rblk_rep     CALL #rbyte         ; принять байт данных
        MOV.B R14, 0(R9)     ; переместить данные из блока
        INC    R15         ; инкремент счётчика положения блока
        INC    R9         ; инкремент указателя блока
        CMP 22(SP), R15     ; проверка завершения данных
        JZ    blk_done     ; повтор до завершения
        CALL    #sack         ; отправить подтверждение (ACK)
        CMP 22(SP), R15     ; проверка завершения данных
        JNZ    rblk_rep     ; повтор до завершения
blk_done  CALL     #nack         ; отправить неподтверждение (NACK)
        CALL    #pbit         ; отправить стоповую посылку
        MOV.B #01h, 30(SP) ; возвращает «1» при успешном завершении
        POP    R13
        POP    R12
        POP    R11
        POP    R10
        POP    R15
        POP    R14
        POP    R9
        POP    R8
        POP    R7
        POP    SR
        RET

;*********************************************************************
; Подпрограммы нижнего уровня, общие для всех протоколов 
;*********************************************************************
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; отправка стартовой последовательности и адреса
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
sbit                     ; «отпустить» обе линии
        BIC.B    #DNC, DIR
; проверка освобождения шины
        MOV    #05h, R10    ; счётчик на 50 микросекунд
wait
        MOV.B IN, R11     ; копировать состояние входов в R11
        AND    #DNC, R11     ; маска входов
        CMP    #DNC, R11     ; если линии SDA или SCL в лог. «0»то шина занята
        JNZ    busy
        DEC    R10         ; декремент счётчика
        JNZ    wait
rsbit   BIC.B    #DNC, DIR     ; дополнительное освобождение линии с целью 
                    ; использования этой же подпрограммы для 
                    ; команды повторяющегося старта
; отправка стартовой последовательности
        BIS.B    #SDA, DIR
        BIS.B    #SCL, DIR
; отправка адреса 
        MOV.B #07h, R13     ; счётчик на 7 бит адреса
        MOV.B R7, R11     ; копировать адрес в R11
ashift  RLA.B    R11         ; сдвиг влево, при этом СЗР 7-битного адреса
; будет находиться  на 7-й позиции
        MOV.B R11, R12     ; скопировать его для возможности маскирования
; без потери данных
        AND.B    #080h, R12     ; маскировать все биты кроме СЗР
        CMP.B #00h, R12     ; сравнить с 0
        JNZ    one
        CALL    #sendzero     ; отправить «1» 
        JMP    zero
one     CALL    #sendone     ; отправить «0»
zero    DEC    R13         ; декремент счётчика
        JNZ    ashift         ; если счётчик <7 бит, повторить сдвиг
        RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; подтверждение (ACK) не принято, отправить STOP и  busy
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
sbusy   CALL    #pbit         ; отправить STOP и  busy 
        ADD    #02h, SP     ; удалить данные из стека, так как
; инструкция RET не использовалась
        MOV.B #00h, 28(SP) ; код ошибки
        POP    R13         ; восстановление регистров
        POP    R12
        POP    R11
        POP    R10
        POP    R15
        POP    R14
        POP    R9
        POP    R8
        POP    R7
        POP    SR
        RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Ожидание подтверждения (ACK)
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
ack
        BIC.B    #SDA, DIR     ; выставить лог. «1» на линии SDA
        BIC.B    #SCL, DIR     ; выставить лог. «1» на линии SCL
; проверка удлинения тактового сигнала (clock low extending),
; чтобы не опережать ведомое устройство
;MOV    #008h, R11     ; счётчик на ?50 мкс
        MOV    #02FFh, R11     ; удлинённый счётчик для батареи PS100Z–200

clkex   MOV.B IN, R10     ; проверка шины
        DEC    R11
        JZ    busy         ; арбитраж – время истекло
        AND.B #SCL, R10     ; проверка линии SCL
        JZ    clkex
; ожидание подтверждения (ACK) (SDA переходит в лог. «0»)
        MOV    #05F6h, R11     ; счётчик таймаута для NACK
wack
        MOV.B IN, R10     ; проверка шины
        DEC    R11
        JZ    sbusy         ; таймаут NACK–– отправить бит P и повторить попытку
        AND.B #SDA, R10     ; маскировать всё, кроме SDA
        JNZ    wack         ; приём ACK или ожидание таймаута
        BIS.B    #SCL, DIR     ; выставить лог. «0» на линии SCL
        RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Отправка стоповой последовательности 
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
pbit
        BIS.B    #SDA, DIR     ; выставить лог. «0» на линии SDA
        BIS.B    #SCL, DIR     ; выставить лог. «0» на линии SCL
        NOP
        BIC.B    #SCL, DIR     ; выставить лог. «1» на линии SCL
        NOP
        BIC.B    #SDA, DIR     ; выставить лог. «1» на линии SDA
        RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Отправка байта (используются также sendzero и sendone)
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
sbyte
; отправка данных 
        MOV.B #08h, R13     ; счётчик на ?50 мкс
        MOV.B R8, R11     ; копировать данные в R11
dshift
        MOV.B R11, R12
        AND.B #080h, R12     ; маскировать все биты, кроме СЗР
        CMP.B #00h, R12     ; сравнить с 0
        JNZ    on
        CALL    #sendzero     ; отправить «1»
        JMP    zer
on      CALL    #sendone     ; отправить «0»
zer
        RLA.B    R11         ; сдвиг влево, отправляемый бит в СЗР
        DEC    R13         ; декремент счётчика на 8 
        JNZ    dshift
        RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Приём байта
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
rbyte
        MOV.B #08h, R12     ; счётчик на 8 бит данных 
        BIC.B    #SDA, DIR     ; выставить лог. «1» на линии SDA
rrep
        BIS.B    #SCL, DIR     ; выставить лог. «0» на линии SCL
        BIC.B    #SCL, DIR     ; выставить лог. «1» на линии SCL
        MOV    #0035h, R13     ; удлинённый счётчик для батареи PS100Z–200
; удлинение тактового сигнала
clkxtn  MOV.B IN, R10     ; проверка шины
        DEC    R13
        JZ    busy         ; выход по таймауту
        AND.B #SCL, R10
        JZ    clkxtn         ; ожидание, если SCL не «1»
        MOV.B IN, R10     ; проверка шины
        RLA.B    R11         ; вход = МЗР
        AND.B    #SDA, R10     ; проверка SDA
        JZ    inzero
        BIS.B    #01h, R11     ; установить «1» в МЗР
inzero  DEC    R12
        JNZ    rrep         ; продолжение для оставшейся части байта
        MOV.B R11, R14     ; копирование данных
        BIS.B    #SCL, DIR     ; выставить лог. «0» на линии SCL
        RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Отправка неподтверждения (NACK)
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
nack
        BIC.B    #SDA, DIR     ; выставить лог. «1» на линии SDA
        BIS.B    #SCL, DIR     ; выставить лог. «0» на линии SCL
        BIC.B    #SCL, DIR     ; выставить лог. «1» на линии SCL
; проверка удлинения тактового сигнала (clock low extending),
; чтобы не опережать ведомое устройство
; ждём установки «1» на линии SCL
clkn    MOV.B IN, R10
        AND.B    #SCL, R10     ; проверка линии SCL
        JZ    clkn
        BIS.B    #SCL, DIR     ; «отпустить» SCL
        RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Отправка подтверждения (ACK)
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
sack                     ; ждём, пока ведомый «отпустит» линию SDA
        MOV    #000Fh, R11     ; счётчик на ?50 мкс
swaita  MOV.B IN, R10     ; проверка шины 
        DEC    R11
        JZ    busy
        AND.B #SDA, R10     ; проверка SCL
        JZ    swaita
        BIS.B    #SDA, DIR     ; перевести SDA в «0»
        BIC.B    #SCL, DIR     ; перевести SCL в «1»
        MOV    #000Fh, R11     ; счётчик на ?50 мкс
swait   MOV.B IN, R10     ; проверка шины
        DEC    R11
        JZ    busy    
        AND.B #SCL, R10     ; проверка SCL
        JZ    swait
        BIS.B    #SCL, DIR     ; перевести SCL в «0»
        BIC.B    #SDA, DIR     ; «отпустить» SDA
        RET
;––– очистка ЖКИ
show_clr
        MOV    #15, r5     ; очистка дисплейной памяти
show_clr1
        MOV.b #0, LCD1–1(r5)
        DEC    r5
        JNZ    show_clr1
        RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Определения для ЖКИ
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
LCD_TYPE
;–––ЖКИ модуля STK/EVK
a       .equ    01h
b       .equ    02h
c       .equ    10h
d       .equ    04h
e       .equ    80h
f       .equ    20h
g       .equ    08h
h       .equ    40h
;––– Определения символов
LCD_Tab .byte   a+b+c+d+e+f     ; отображает”0”
        .byte    b+c         ; отображает”1”
        .byte    a+b+d+e+g     ; отображает”2”
        .byte    a+b+c+d+g     ; отображает”3”
        .byte    b+c+f+g     ; отображает”4”
        .byte     a+c+d+f+g     ; отображает”5”
        .byte    a+c+d+e+f+g     ; отображает”6”
        .byte    a+b+c         ; отображает”7”
        .byte    a+b+c+d+e+f+g ; отображает”8”
        .byte    a+b+c+d+f+g ; отображает”9”
        .byte    0         ; отображает ”:” пустой
        .byte    g         ; отображает”;” –
        .byte    a+d+e+f     ; отображает”<” [
        .byte    d+g         ; отображает”=”
        .byte    a+b+c+d     ; отображает”>” ]
        .byte    a+b+e+g     ; отображает”?”
        .byte    a+b+d+e+f+g ; отображает”@”
        .byte    a+b+c+e+f+g ; отображает”A”
        .byte    c+d+e+f+g     ; отображает”B” b
        .byte    a+d+e+f     ; отображает”C”
        .byte    b+c+d+e+g     ; отображает”D” d
        .byte    a+d+e+f+g     ; отображает”E”
        .byte    a+e+f+g     ; отображает”F”
        .byte    a+b+c+d+f+g ; отображает”G”
        .byte    b+c+e+f+g     ; отображает”H”
        .byte    b+c         ; отображает”I”
        .byte    b+c+d+e     ; отображает”J”
        .byte    0         ; отображает”K”
        .byte    d+e+f         ; отображает”L”
        .byte    a+b+c+e+f     ; отображает”M”
        .byte    c+e+g         ; отображает”N” n
        .byte    c+d+e+g     ; отображает”O” o
        .byte    a+b+e+f+g     ; отображает”P”
        .byte    0         ; отображает”Q”
        .byte    e+g         ; отображает”R” r
        .byte    a+c+d+f+g     ; отображает”S”
        .byte    d+e+f+g     ; отображает”T” t
        .byte    c+d+e         ; отображает”U” u
        .byte     0         ; отображает”V”
        .byte    0         ; отображает”W”
        .byte    0         ; отображает”X”
        .byte    b+c+d+f+g     ; отображает”Y”
        .byte    a+b+d+e+g     ; отображает”Z” 2
LCD_Tab_End
        .even
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Вектора прерываний 
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; .sect ”Int_Vect”,0FFFFh–1 ; без программы монитора
; .word RESET     ; POR, внеш. Reset, Watchdog
; .end
        .sect ”Int_Vect”,05FFh–1 ; с программой монитора
        .word RESET         ; POR, внеш. Reset, Watchdog
        .end
    
Приложение B Программа поиска адресов
;****************************************************************************
; Программа поиска адресов
;––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
; Программа сканирует шину SMBus на предмет подключенных устройств. 
; Начинает с адреса 0x00 и перебирает все 128 возможных адресов. 
; Текущий адрес при сканировании отображается на правой части ЖКИ
; На левой части отображается адрес последнего из найденных устройств. Когда устройство
; найдено, программа приостанавливается, адрес переносится в левую часть ЖКИ, после 
; чего выполнение продолжается.
; Наличие  устройства на шине проверяется посылкой стартовой последовательности, 
; адреса устройства и ожидания подтверждения. Далее тестируется следующий адрес.
;
; Программа поиска адресов является примером удаления неиспользуемых частей кода.
; Т.к. ей не требуются некоторые протоколы, некоторые подпрограммы 
; верхнего и нижнего уровней были удалены.
;****************************************************************************
RAM_orig        .set     00240h     ; Стартовый адрес
SP_orig         .set     005DEh     ; указатель стека
;––– Определения управляющих регистров
WDTCTL          .equ     0120h
WDTHold         .equ     80h
WDT_wrkey       .equ     05A00h
;PORT 0
P0IE            .equ     015h
P0DIR           .equ     012h
P0IN            .equ     010h
P0OUT           .equ     011h
; port 2
P2IN            .equ     028h
P2OUT           .equ     029h
P2IE            .equ     02Dh
P2SEL           .equ     02Eh
P2DIR           .equ     02Ah
SDA             .equ     020h
SCL             .equ     080h
DNC             .equ     0A0h
OUT             .equ     P2OUT
DIR             .equ     P2DIR
IN              .equ     P2IN
LCD1            .equ     031h
LCDM            .equ     030h
IE1             .equ     0h
IE2             .equ     01h
IFG1            .equ     02h
IFG2            .equ     03h
address         .equ     0500h         ; Адрес в ОЗУ для переменной сканирования 
;****************************************************************************
; Reset : Инициализация процессора
;****************************************************************************
        .sect    ”MAIN”,RAM_orig
        RESET
        MOV    #SP_orig,SP    ; Инициализация указателя стека
;****************************************************************************
; Начало пользовательской программы
;****************************************************************************
        CALL    #show_clr
; Сброс адреса
res     MOV.B #00FFh, address ; адрес начинается с 0xFF
; Начало цикла перебора адресов
retry
        INC.B    address     ; переход к следующему адресу из 0xFF в 0x00
        CMP.B     #080h, address ; адрес = 80?
        JZ    res         ; сброс адреса по переполнению
; пауза
        MOV    #02Fh, R7     ; цикл паузы
dela2   MOV    #031Fh, R6
dela    DEC    R6
        JNZ    dela
        DEC    R7
        JNZ    dela2
; Отображение сканируемого адреса
        MOV    #0000h, R5     ; очистка (убедиться, что очищается старший байт)
        MOV.B address, R5     ; R5 ? младший байт
        AND    #000Fh, R5     ; маска на старшую тетраду
        MOV.B LCD_Tab(R5),LCD1+1 
; отобразить младшую тетраду 0–F
        MOV.B address, R5     ; R5 ? младший байт
        AND    #00F0h, R5     ; маска на младшую тетраду
        RRA    R5         ; сдвиг вправо
        RRA    R5         ; сдвиг вправо
        RRA    R5         ; сдвиг вправо
        RRA     R5         ; сдвиг вправо
        MOV.B LCD_Tab(R5), LCD1+2 
; отобразить старшую тетраду 0–F
        PUSH    #00h         ; место для кода ошибки
        PUSH    address     ; поместить адрес в стек
        SUB     #06, SP
        CALL     #hunt
        POP     R10         ; вернуть данные в R10
        POP     R11         ; вернуть данные в R11
        ADD     #04h, SP     ; освободить место для адреса и команд
        POP    R9         ; вернуть код ошибки
        CMP    #00h, R9
        JZ    retry         ; повтор при неудаче
        MOV    #0FFh, R7
dela4   MOV    #0B4Fh, R6
dela3   DEC    R6
        JNZ    dela3
        DEC    R7
        JNZ    dela4
        MOV    #0000h, R5     ; очистка (убедиться, что очищается старший байт)
        MOV.B address, R5     ; R5 ? младший байт
        AND    #000Fh, R5     ; маска на старшую тетраду
        MOV.B LCD_Tab(R5),LCD1+4 
; отобразить младшую тетраду 0–F
        MOV.B address, R5     ; R5 ? младший байт
        AND    00F0h, R5     ; маска на младшую тетраду    
        RRA    R5         ; сдвиг вправо
        RRA    R5         ; сдвиг вправо
        RRA     R5         ; сдвиг вправо
        RRA     R5         ; сдвиг вправо
        MOV.B LCD_Tab(R5), LCD1+5 
; отобразить старшую тетраду 0–F
        JMP    retry         ; повтор для следующего адреса
;****************************************************************************
; Завершение пользовательской программы
;****************************************************************************

;****************************************************************************
; Подпрограммы верхнего уровня, п/п нижнего уровня вызываются индивидуально 
; для реализации различных протоколов 
;****************************************************************************

;****************************************************************************
; Поиск это модифицированная часть протокола «Чтение байта»
;****************************************************************************

hunt    PUSH    SR
        PUSH    R7
        PUSH    R8
        PUSH    R9
        PUSH    R14
        PUSH    R15
        PUSH    R10
        PUSH    R11
        PUSH    R12
        PUSH    R13
        MOV.B 26(SP), R8     ; параметр команды
        MOV.B 28(SP), R7     ; параметр адреса
        CALL    #sbit         ; отправить стартовую последовательность и адрес
        CALL    #sendzero     ; отправить 0 для записи
        CALL    #ack         ; ждём подтверждения (ACK)
        MOV.B #01h, 30(SP) ; возвращает «1» при успешном завершении
        POP    R13
        POP    R12
        POP    R11
        POP    R10
        POP    R15
        POP    R14
        POP    R9
        POP    R8
        POP    R7
        POP    SR
        RET
;****************************************************************************
; Подпрограммы нижнего уровня, общие для всех протоколов
;****************************************************************************
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; отправка стартовой последовательности и адреса
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
sbit                     ; «отпустить» обе линии
        BIC.B    #DNC, DIR
; проверка освобождения шины
        MOV    #05h, R10    ; счётчик на 50 микросекунд
wait
        MOV.B IN, R11     ; копировать состояние входов в R11
        AND    #DNC, R11     ; маска входов
        CMP    #DNC, R11     ; если линии SDA или SCL в лог. «0»то шина занята
        JNZ    busy
        DEC    R10         ; декремент счётчика
        JNZ    wait
rsbit   BIC.B    #DNC, DIR     ; дополнительное освобождение линии с целью 
                    ; использования этой же подпрограммы для 
                    ; команды повторяющегося старта
; отправка стартовой последовательности
        BIS.B    #SDA, DIR
        BIS.B    #SCL, DIR
; отправка адреса 
        MOV.B #07h, R13     ; счётчик на 7 бит адреса
        MOV.B R7, R11     ; копировать адрес в R11
ashift  RLA.B    R11         ; сдвиг влево, при этом СЗР 7-битного адреса
; будет находиться  на 7-й позиции
        MOV.B R11, R12     ; скопировать его для возможности маскирования
; без потери данных
        AND.B    #080h, R12     ; маскировать все биты кроме СЗР
        CMP.B #00h, R12     ; сравнить с 0
        JNZ    one
        CALL    #sendzero     ; отправить «1» 
        JMP    zero
one     CALL    #sendone     ; отправить «0»
zero    DEC    R13         ; декремент счётчика
        JNZ    ashift         ; если счётчик <7 бит, повторить сдвиг
        RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; подтверждение (ACK) не принято, отправить STOP и  busy
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
sbusy   CALL    #pbit         ; отправить STOP и  busy 
        ADD    #02h, SP     ; удалить данные из стека, так как
; инструкция RET не использовалась
        MOV.B #00h, 28(SP) ; код ошибки
        POP    R13         ; восстановление регистров
        POP    R12
        POP    R11
        POP    R10
        POP    R15
        POP    R14
        POP    R9
        POP    R8
        POP    R7
        POP    SR
        RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Обработка занятости системы
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
busy3   ADD    #06h, SP     ; удаление лишних данных процедур sendone или sendzero
busy    ADD    #02h, SP     ; удалить данные из стека, так как
; инструкция RET не использовалась

        MOV.B #00h, 28(SP) ; код ошибки
        POP    R13         ; восстановление регистров
        POP    R12
        POP    R11
        POP    R10
        POP    R15
        POP    R14
        POP    R9
        POP    R8
        POP    R7
        POP    SR
        RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Отправить «1»
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
sendone PUSH    R10
        PUSH    R11
        BIC.B    #SDA, DIR     ; установить лог. «1» на линии  SDA
        BIC.B    #SCL, DIR     ; установить лог. «1» на линии  SCL
; проверка удлинения тактового сигнала (clock low extending),
; чтобы не опережать ведомое устройство
        MOV.B #04h, R11     ; установить число тактов для верного времени
clkext  MOV.B IN, R10     ; проверка шины
        DEC    R11
        JZ     busy3         ; арбитраж – время истекло
        AND.B #SCL, R10     ; проверка линии SCL
        JZ    clkext
; арбитраж: убедиться, что на линии SDA действительно лог. «1», иначе приоритет
; отдаётся другому ведущему устройству
        MOV.B IN, R10     ; проверка шины
        AND.B #SDA, R10     ; маскировать всё, кроме SDA
        JZ     busy3
        BIS.B #SCL, DIR     ; освободить линию SCL
        MOV.B IN, R10     ; определение повторяющейся 
; стартовой последовательности
        AND.B #SDA, R10
        JZ    busy3
        POP    R11
        POP    R10
        RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Отправить «0»
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
sendzero
        PUSH    R10
        PUSH    R11
        BIS.B #SDA, DIR     ; выставить лог. «0» на линии SDA
        BIC.B #SCL, DIR     ; выставить лог. «1» на линии SCL
; проверка удлинения тактового сигнала (clock low extending),
; чтобы не опережать ведомое устройство
        MOV    #04h, R11     ; счётчик времени перехода SCL в «1»
clke    MOV.B IN, R10     ; проверка шины
        DEC    R11
        JZ    busy3         ; арбитраж – время истекло
        AND.B #SCL, R10     ; проверка линии SCL
        JZ    clke
        BIS.B #SCL, DIR     ; освободить линию SCL
        POP    R11
        POP    R10
        RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Ожидание подтверждения (ACK)
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
ack
        BIC.B    #SDA, DIR     ; выставить лог. «1» на линии SDA
        BIC.B    #SCL, DIR     ; выставить лог. «1» на линии SCL
; проверка удлинения тактового сигнала (clock low extending),
; чтобы не опережать ведомое устройство
;MOV    #008h, R11     ; счётчик на ?50 мкс
        MOV    #02FFh, R11     ; удлинённый счётчик для батареи PS100Z–200
clkex   MOV.B IN, R10     ; проверка шины
        DEC    R11
        JZ    busy         ; арбитраж – время истекло
        AND.B #SCL, R10     ; проверка линии SCL
        JZ    clkex
; ожидание подтверждения (ACK) (SDA переходит в лог. «0»)
        MOV    #05F6h, R11     ; счётчик таймаута для NACK
wack
        MOV.B IN, R10     ; проверка шины
        DEC    R11
        JZ    sbusy         ; таймаут NACK–– отправить бит P и повторить попытку
        AND.B #SDA, R10     ; маскировать всё, кроме SDA
        JNZ    wack         ; приём ACK или ожидание таймаута
        BIS.B    #SCL, DIR     ; выставить лог. «0» на линии SCL
        RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Отправка стоповой последовательности 
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
pbit
        BIS.B    #SDA, DIR     ; выставить лог. «0» на линии SDA
        BIS.B    #SCL, DIR     ; выставить лог. «0» на линии SCL
        NOP
        BIC.B    #SCL, DIR     ; выставить лог. «1» на линии SCL
        NOP
        BIC.B    #SDA, DIR     ; выставить лог. «1» на линии SDA
        RET
;––– очистка ЖКИ
show_clr
        MOV    #15, r5     ; очистка дисплейной памяти
show_clr1
        MOV.b #0, LCD1–1(r5)
        DEC    r5
        JNZ    show_clr1
        RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Определения для ЖКИ
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
LCD_TYPE
;–––ЖКИ модуля STK/EVK
a         .equ    01h
b         .equ    02h
c         .equ    10h
d         .equ    04h
e         .equ    80h
f         .equ    20h
g         .equ    08h
h         .equ    40h
LCD_Tab   .byte    a+b+c+d+e+f    ;отображает ”0”
          .byte     b+c         ; отображает”1”
          .byte     a+b+d+e+g     ; отображает”2”
          .byte     a+b+c+d+g     ; отображает”3”
          .byte     b+c+f+g     ; отображает”4”
          .byte     a+c+d+f+g     ; отображает”5”
          .byte     a+c+d+e+f+g     ; отображает”6”
          .byte     a+b+c         ; отображает”7”
          .byte     a+b+c+d+e+f+g ; отображает”8”
          .byte     a+b+c+d+f+g     ; отображает”9”
          .byte     a+b+c+e+f+g     ; отображает”A”
          .byte     c+d+e+f+g     ; отображает”B” b
          .byte     a+d+e+f     ; отображает”C”
          .byte     b+c+d+e+g     ; отображает”D” d
          .byte     a+d+e+f+g     ; отображает”E”
          .byte     a+e+f+g     ; отображает”F”
LCD_Tab_End
          .even
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Вектора прерываний 
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
          .sect     ”Int_Vect”,05FFh–1 ; с программой монитора
          .word     RESET ; POR, внеш. Reset, Watchdog
          .end

Приложение C Программа работы со смарт-батареей

;****************************************************************************
; Программа SBData
; ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
; Читает температуру, напряжение, производителя, хим. конфигурацию, ёмкость, и 
; предупреждение об оставшейся ёмкости из монитора батареи с шиной SMBus. 
; Также производится запись в регистр «Предупреждение об оставшейся ёмкости» 
; (RemainingCapacityAlarm).
;
; В данном частном случае применялся батарейный смарт-модуль PowerSmart PS100Z–200
; Другие данные из батареи можно читать, меняя команды.
; Контроллер смарт-батареи PowerSmart поддерживает стандарт SMBus V1.0 
; и спецификацию Smart Battery data 
; Настоящая конфигурация программы написана для использования с пользовательской 
; программой под управлением программы монитора
; на отладочной плате 337 EVK, подпрограммы SMBus находятся в EPROM. Также требуется 
; Таблица ASCII символов для ЖКИ 
; Здесь использован файл ASCII.txt. На него ссылается указатель alcd.
;****************************************************************************
RAM_orig  .set    00240h     ; Стартовый адрес
SP_orig   .set     005DEh     ; указатель стека
EPROM     .set     08850h     ; Размещение EPROM
;––– Определения управляющих регистров
WDTCTL    .equ     0120h
WDTHold   .equ     80h
WDT_wrkey .equ     05A00h
;PORT 0 
P0IE      .equ     015h
P0DIR     .equ     012h
P0IN      .equ     010h
P0OUT     .equ     011h
; port 2
P2IN      .equ     028h
P2OUT     .equ     029h
P2IE      .equ     02Dh
P2SEL     .equ     02Eh
P2DIR     .equ     02Ah
SDA       .equ     020h
SCL       .equ     080h
DNC       .equ     0A0h
OUT       .equ     P2OUT
DIR       .equ     P2DIR
IN        .equ     P2IN
LCD1      .equ     031h
LCDM      .equ     030h
IE1       .equ     0h
IE2       .equ     01h
IFG1      .equ     02h
IFG2      .equ     03h
block     .equ     0550h
alcd      .equ     0B500h    ; Размещение таблицы символов ASCII для ЖКИ
;****************************************************************************
; Reset : Initialize processor
;****************************************************************************
          .sect     ”MAIN”,RAM_orig
RESET
        MOV    #SP_orig,SP     ; Инициализация указателя стека
;****************************************************************************
; Начало пользовательской программы
;****************************************************************************
repeat
        CMP.B #0FFh, R8
        JNZ    skp
        INC.B    R7         ; инкремент старшего байта значения
; для протокола записи слова
        MOV.B #00h, R8
skp
        INC.B    R8         ; инкремент значения
; для протокола записи слова
skp0
; Чтение температуры
        CALL    #show_clr
        PUSH    #00h         ; место для кода ошибки
        PUSH    #000Bh     ; поместить адрес в стек
        PUSH    #008h         ; поместить команду чтения 
; температуры батареи
        PUSH    #00h         ; зарезервировать байт для данных 
        PUSH    #00h         ; зарезервировать байт для данных
        CALL    #rwp
        POP    R10         ; поместить данные в R10
        POP    R11         ; поместить данные в R11
        ADD    #04h, SP     ; освободить место команды и адреса
        POP    R9         ; читать код ошибки
        CMP    #00h, R9
        JZ    skp0         ; повтор при неудаче
        RLA    R11
        RLA    R11
        RLA    R11
        RLA    R11
        RLA    R11
        RLA    R11
        RLA    R11
        RLA    R11
        XOR    R10, R11     ; объединить 2 байта данных
        MOV    R11, R12
        SUB    #0AAAh, R12     ; перевод в градусы Цельсия 
        CALL    #display     ; вызов подпрограммы отображения 
        XOR.B #40h, LCD1+1 
; добавить децимальную точку
        MOV.B alcd+’T’, LCD1+5
        CALL    #delay     ; вызов подпрограммы задержки
skp1         ; чтение напряжения 
        CALL    #show_clr
        PUSH    #00h         ; место для кода ошибки
        PUSH    #000Bh     ; поместить адрес в стек
        PUSH    #009h         ; поместить в стек команду
; чтения напряжения батареи 
        PUSH    #00h         ; зарезервировать байт для данных
        PUSH    #00h         ; зарезервировать байт для данных
        CALL    #rwp
        POP    R10         ; поместить данные в R10
        POP    R11         ; поместить данные в R11
        ADD    #04h, SP     ; освободить место команды и адреса
        POP    R9         ; читать код ошибки
        CMP    #00h, R9
        JZ    skp1         ; повтор при неудаче
        RLA    R11
        RLA    R11
        RLA    R11
        RLA    R11
        RLA    R11
        RLA    R11
        RLA    R11
        RLA    R11
        XOR    R10, R11     ; объединить 2 байта данных
        MOV    R11, R12
        CALL    #display     ; вызов подпрограммы отображения
        XOR.B #40h, LCD1+3 
; добавить децимальную точку
        MOV.B alcd+’U’, LCD1+5
        CALL    #delay     ; вызов подпрограммы задержки
skp2         ; чтение названия производителя
        CALL    #show_clr
        PUSH    #00h         ; место для кода ошибки
        PUSH    #000Bh     ; поместить адрес в стек
        PUSH    #0020h     ; поместить в стек команду
; чтения имени производителя
        PUSH    #block         ; зарезервировать байт для данных
        PUSH    #00h         ; зарезервировать байт для данных
        CALL    #blkr
        POP    R10         ; поместить данные в R10
        ADD    #06h, SP
        POP    R9         ; читать код ошибки
        CMP    #00h, R9
        JZ    skp2         ; повтор при неудаче
        MOV.B block, R5     ; копировать символ
        MOV.B alcd(R5), LCD1+6 
; отобразить символ
        MOV.B block+1, R5     ; копировать символ
        MOV.B alcd(R5), LCD1+5 
; отобразить символ
        MOV.B block+2, R5     ; копировать символ
        MOV.B alcd(R5), LCD1+4 
; отобразить символ
        MOV.B block+3, R5     ; копировать символ
        MOV.B alcd(R5), LCD1+3 
; отобразить символ
        MOV.B block+4, R5     ; копировать символ
        MOV.B alcd(R5), LCD1+2 
; отобразить символ
        MOV.B block+5, R5     ; копировать символ
        MOV.B alcd(R5), LCD1+1 
; отобразить символ
        MOV.B block+6, R5     ; копировать символ
        MOV.B alcd(R5), LCD1+0 
; отобразить символ
        CALL    #delay     ; вызов подпрограммы задержки
skp3     ; чтение химической конфигурации 
        CALL    #show_clr
        PUSH    #00h         ; место для кода ошибки
        PUSH    #000Bh     ; поместить адрес в стек
        PUSH    #0022h     ; поместить в стек команду
; чтения химической конфигурации
        PUSH #block         ; зарезервировать байт для данных
        PUSH    #00h         ; зарезервировать байт для данных
        CALL    #blkr
        POP    R10         ; поместить данные в R10
        ADD    #06h, SP
        POP    R9         ; читать код ошибки
        CMP    #00h, R9
        JZ    skp3         ; повтор при неудаче
        MOV.B block, R5     ; копировать символ
        MOV.B alcd(R5), LCD1+6 
; отобразить символ
        MOV.B block+1, R5     ; копировать символ
        MOV.B alcd(R5), LCD1+5 
; отобразить символ
        MOV.B block+2, R5     ; копировать символ
        MOV.B alcd(R5), LCD1+4 
; отобразить символ
        MOV.B block+3, R5     ; копировать символ
        MOV.B alcd(R5), LCD1+3 
; отобразить символ
        CALL     #delay     ; вызов подпрограммы задержки
skp4     ; чтение ёмкости батареи
        CALL    #show_clr
        PUSH    #00h         ; место для кода ошибки
        PUSH    #000Bh     ; поместить адрес в стек
        PUSH    #0018h     ; поместить в стек команду
; чтения ёмкости батареи
        PUSH    #00h         ; зарезервировать байт для данных
        PUSH    #00h         ; зарезервировать байт для данных
        CALL    #rwp
        POP    R10         ; поместить данные в R10
        POP    R11         ; поместить данные в R11
        ADD     #04h, SP     ; освободить место команды и адреса
        POP     R9         ; читать код ошибки
        CMP     #00h, R9
        JZ     skp4         ; повтор при неудаче
        RLA     R11
        RLA     R11
        RLA     R11
        RLA     R11
        RLA     R11
        RLA     R11
        RLA     R11
        RLA     R11
        XOR     R10, R11
        MOV     R11, R12
        CALL     #display     ; вызов подпрограммы отображения 
        XOR.B #40h, LCD1+3 
; добавить децимальную точку
        MOV.B alcd+’A’, LCD1+1
        MOV.B alcd+’H’, LCD1+0
        CALL     #delay     ; вызов подпрограммы задержки 
skp5         ; запись предупреждения об оставшейся ёмкости (RemainingCapacityAlarm)
        CALL     #show_clr
        PUSH     #00h         ; место для кода ошибки
        PUSH     #000Bh     ; поместить адрес в стек
        PUSH     #001h         ; поместить в стек команду
        PUSH     R8         ; зарезервировать байт для данных
        PUSH     R7         ; зарезервировать байт для данных
        CALL     #wwp
        POP     R11         ; поместить данные в R11
        POP     R10         ; поместить данные в R10
        ADD     #04h, SP     ; освободить место команды и адреса
        POP     R9         ; читать код ошибки
        CMP     #00h, R9
        JZ     skp5         ; повтор при неудаче
        RLA     R11
        RLA     R11
        RLA     R11
        RLA     R11
        RLA     R11
        RLA     R11
        RLA     R11
        RLA     R11
        XOR     R10, R11
        MOV     R11, R12
        CALL     #display     ; вызов подпрограммы отображения
        MOV.B alcd+’S’, LCD1+6
        CALL     #delay     ; вызов подпрограммы задержки
skp6         ; считывание оставшейся ёмкости (RemainingCapacityAlarm)
        CALL     #show_clr
        PUSH     #00h         ; место для кода ошибки
        PUSH     #000Bh     ; поместить адрес в стек
        PUSH     #001h         ; поместить в стек команду
        PUSH     #00h         ; зарезервировать байт для данных
        PUSH     #00h         ; зарезервировать байт для данных
        CALL     #rwp
        POP     R10         ; поместить данные в R10
        POP     R11         ; поместить данные в R11
        ADD     #04h, SP     ; освободить место команды и адреса
        POP     R9         ; читать код ошибки
        CMP     #00h, R9
        JZ     skp6         ; повтор при неудаче
        RLA     R11
        RLA     R11
        RLA     R11
        RLA     R11
        RLA     R11
        RLA     R11
        RLA     R11
        RLA     R11
        XOR     R10, R11
        MOV     R11, R12
        CALL     #display     ; вызов подпрограммы отображения
        MOV.B alcd+’R’, LCD1+6
        CALL    #delay     ; вызов подпрограммы задержки
        JMP     repeat         ; завершение программы, бесконечный цикл
;****************************************************************************
; Окончание пользовательской программы
;****************************************************************************

delay
        PUSH     R6
        PUSH     R7
        MOV     #00DFh, R7     ; вложенный цикл задержки 
dela4   MOV     #0D40h, R6
dela3   DEC     R6
        JNZ     dela3
        DEC     R7
        JNZ     dela4
        POP     R7
        POP     R6
        RET
display     ; подпрограмма отображения
        PUSH     R5
        PUSH     R12
        PUSH     R13
        PUSH     R14
        PUSH     R15
        MOV     #16, R15     ; процедура преобразования hex ? BCD
        CLR     R14         ; входные значения в R12, выходные в R13 и R14
        CLR     R13
ls1     RLA     R12
        DADD R13, R13
        DADD R14, R14
        DEC     R15
        JNZ     ls1
        MOV.B R13, R5     ; поместить 2 младших BCD-разряда в R5
        AND     #000Fh, R5     ; маскировать всё, кроме младшей тетрады
        MOV.B LCD_Tab(R5),LCD1+0 
; Отобразить младшую тетраду
        MOV.B R13, R5 
; поместить 2 младших BCD-разряда в R5
        AND     #00F0h, R5     ; маскировать всё, кроме старшей тетрады
        RRA     R5         ; сдвиг вправо 
        RRA     R5         ; сдвиг вправо 
        RRA     R5         ; сдвиг вправо
        RRA     R5         ; сдвиг вправо
        MOV.B LCD_Tab(R5), LCD1+1 
; Отобразить старшую тетраду
        SWPB R13         ; обмен байтами в R13
        MOV.B R13, R5     ; поместить 2 старших BCD-разряда в R5
        AND     #000Fh, R5     ; маскировать всё, кроме младшей тетрады
        MOV.B LCD_Tab(R5),LCD1+2 
; Отобразить младшую тетраду
        MOV.B R13, R5     ; поместить 2 старших BCD-разряда в R5
        AND     #00F0h, R5     ; маскировать всё, кроме старшей тетрады
        RRA     R5         ; сдвиг вправо
        RRA     R5         ; сдвиг вправо
        RRA     R5         ; сдвиг вправо
        RRA     R5         ; сдвиг вправо
        MOV.B LCD_Tab(R5), LCD1+3 
; Отобразить старшую тетраду
        MOV.B R14, R5     ; поместить 2 младших BCD-разряда в R5
        AND     #000Fh, R5     ; маскировать всё, кроме младшей тетрады
        MOV.B LCD_Tab(R5),LCD1+4 
; Отобразить младшую тетраду
        MOV.B R14, R5     ; поместить 2 младших BCD-разряда в R5
        AND     #00F0h, R5     ; маскировать всё, кроме старшей тетрады
        RRA     R5         ; сдвиг вправо
        RRA     R5         ; сдвиг вправо
        RRA     R5         ; сдвиг вправо
        RRA     R5         ; сдвиг вправо
        MOV.B LCD_Tab(R5), LCD1+5 
; Отобразить старшую тетраду
        POP     R15
        POP     R14
        POP     R13
        POP     R12
        POP     R5
        RET
.sect ”smbus”, EPROM
;****************************************************************************
; Подпрограммы верхнего уровня, п/п нижнего уровня вызываются индивидуально 
; для реализации различных протоколов 
;****************************************************************************
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Протокол «Быстрая команда» 1
; ==========================================================================
; Влияние на регистры: нет
; Влияние на память: стек, максимум 40 байт
; ––––––––––––––––––––––––––-––––––––––––––––––––––––––-–––––––––––––––––––––
; Описание     Шаг                     Направление
; ––––––––––––––––––––––––––––––––––––––––––––––––––––-––––––––––––––––––––––
;         старт (start)                 из
;         адрес(address)             из
;         чтение/запись(R/W)             из
;         подтверждение(acknowledge)     в   ?
;         стоп (stop)                 из
;
; Параметры в стеке
; ––––––––––––––––––––
; флаг ошибки    error_flag    младшая область памяти    low mem
; не используется    unused
; не используется    unused
; не используется    unused
; адрес        address    старшая область памяти    high mem
;
; Пример использования 
; ––––––––––––––
;     PUSH    #00h        ; место для кода ошибки
;     PUSH    #00Bh        ; поместить адрес в стек
;     SUB    #06h, SP     ; остальные параметры не используются
;     CALL    #qcp
;     ADD    #08h, SP    ; вычесть объём параметров
;     POP    R9         ; читать из стека код ошибки
;     CMP    #00h, R9
;     JZ    error         ; ошибочное завершение – вызов обработчика ошибок
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
qcp
PUSH     SR
PUSH     R7
PUSH     R8
PUSH     R9
PUSH     R14
PUSH     R15
PUSH     R10
PUSH     R11
PUSH     R12
PUSH     R13
MOV.B 28(SP), R7     ; получить адрес из стека
CALL    #sbit         ; отправить стартовую посылку и адрес
;CALL    #sendone     ; отправить «1» или
CALL    #sendzero     ; отправить «0»
CALL    #ack         ; ждём подтверждения (ACK)
CALL    #pbit         ; отправить стоповую посылку
MOV.B #01h, 30(SP) ; возвращает «1» при успешном завершении
POP    R13
POP    R12
POP    R11
POP    R10
POP    R15
POP    R14
POP    R9
POP    R8
POP    R7
POP    SR
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Протокол «Записать байт» 4
; ==========================================================================
; Влияние на регистры: нет
; Влияние на память: стек, максимум 40 байт
; ––––––––––––––––––––––––––-––––––––––––––––––––––––––-––––––––––––––––––––––––
; Описание     Шаг                     Направление
; ––––––––––––––––––––––––––––––––––––––––––––––––––––-–––––––––––––––––––––––––
;         старт (start)                 из
;        адрес(address)             из
;        чтение/запись(R/W)             из
;        подтверждение(acknowledge)     в   ?
;         команда (command)            из
;        подтверждение(acknowledge)     в   ?
;         данные (data)                из
;        подтверждение(acknowledge)     в   ?
;         стоп (stop)                 из
;
; Параметры в стеке
; ––––––––––––––––––––
; флаг ошибки    error_flag    младшая область памяти    low mem
; не используется    unused
; данные         data
; команда         command
; адрес        address    старшая область памяти    high mem
;
; Пример использования 
; ––––––––––––––
;     PUSH    #00h        ; место для кода ошибки
;     PUSH    #00Bh        ; поместить адрес в стек
;     PUSH    #001h        ; поместить команду в стек
;     PUSH    #055h         ; отправляемые данные 
;     SUB    #02h, SP     ; остальные параметры не используются
;     CALL #wbp
;     ADD    #08h, SP    ; вычесть объём параметров
;     POP    R9         ; читать из стека код ошибки
;     CMP    #00h, R9
;     JZ    error         ; ошибочное завершение – вызов обработчика ошибок

wbp
PUSH     SR
PUSH     R7
PUSH     R8
PUSH     R9
PUSH     R14
PUSH     R15
PUSH     R10
PUSH     R11
PUSH     R12
PUSH     R13
MOV.B 26(SP), R8     ; параметр команды
MOV.B 28(SP), R7     ; параметр адреса
CALL     #sbit         ; отправить стартовую посылку и адрес
CALL     #sendzero     ; отправить «0» для записи
CALL     #ack         ; ждём подтверждения (ACK)
CALL     #sbyte     ; отправить код команды
CALL     #ack         ; ждём подтверждения (ACK)
MOV.B 24(SP), R8     ; отправка данных 
CALL     #sbyte     ; отправить байт данных
CALL     #ack         ; ждём подтверждения (ACK)
CALL     #pbit         ; отправить стоповую посылку
MOV.B #01h, 30(SP) ; возвращает «1» при успешном завершении
POP     R13
POP     R12
POP     R11
POP     R10
POP     R15
POP     R14
POP     R9
POP     R8
POP     R7
POP     SR
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Протокол «Записать слово» 5
; ==========================================================================
; Влияние на регистры: нет
; Влияние на память: стек, максимум 40 байт
; ––––––––––––––––––––––––––-––––––––––––––––––––––––––-––––––––––––––––––––
; Описание     Шаг                     Направление
; ––––––––––––––––––––––––––––––––––––––––––––––––––––-–––––––––––––––––––––
;         старт (start)                 из
;        адрес(address)             из
;        чтение/запись(R/W)             из
;        подтверждение(acknowledge)     в   ?
;         данные (data)                из
;        подтверждение(acknowledge)     в   ?
;         данные (data)                из
;        подтверждение(acknowledge)     в   ?
;         стоп (stop)                 из

; Параметры в стеке
; ––––––––––––––––––––
; флаг ошибки        error_flag    младшая область памяти    low mem
; не используется        unused
; данные             data
; команда             command
; адрес            address    старшая область памяти    high mem

; –––––––––––––––––
; Пример использования 
; ––––––––––––––
;       PUSH    #00h        ; место для кода ошибки
;       PUSH    #00Bh        ; поместить адрес в стек
;       PUSH    #001h        ; код команды
;       PUSH    #0AAh        ; младший отправляемый байт
;       PUSH    #055h        ; старший отправляемый байт
;       CALL    #wwp
;       ADD     #08h, SP    ; освободить место, занимаемое параметрами 
;       POP     R9         ; читать из стека код ошибки
;       CMP     #00h, R9
;       JZ      error         ; ошибочное завершение – вызов обработчика ошибок
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
wwp
PUSH     SR
PUSH     R7
PUSH     R8
PUSH     R9
PUSH     R14
PUSH     R15
PUSH     R10
PUSH     R11
PUSH     R12
PUSH     R13
MOV.B 26(SP), R8     ; параметр команды
MOV.B 28(SP), R7     ; параметр адреса
CALL     #sbit         ; отправить стартовую посылку и адрес
CALL     #sendzero     ; отправить «0» для записи
CALL     #ack         ; ждём подтверждения (ACK)
CALL     #sbyte     ; отправить код команды
CALL     #ack         ; ждём подтверждения (ACK)
MOV.B 24(SP), R8     ; данные для записи – младший байт
CALL     #sbyte     ; отправить младший байт данных
CALL     #ack         ; ждём подтверждения (ACK)
MOV.B 22(SP), R8     ; данные для записи – старший байт
CALL     #sbyte     ; отправить старший байт данных
CALL     #ack         ; ждём подтверждения (ACK)
CALL     #pbit         ; отправить стоповую посылку
MOV.B #01h, 30(SP) ; возвращает «1» при успешном завершении
POP     R13
POP     R12
POP     R11
POP     R10
POP     R15
POP     R14
POP     R9
POP     R8
POP     R7
POP     SR
RET

; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Протокол «Читать байт» 6
; ==========================================================================
; Влияние на регистры: нет
; Влияние на память: стек, максимум 40 байт
; ––––––––––––––––––––––––––-––––––––––––––––––––––––––-––––––––––––––––––––––––
; Описание     Шаг                     Направление
; ––––––––––––––––––––––––––––––––––––––––––––––––––––-–––––––––––––––––––––––––
;         старт (start)                 из
;        адрес(address)             из
;        чтение/запись(R/W)             из
;        подтверждение(acknowledge)     в   ?
;         команда (command)            из
;        подтверждение(acknowledge)     в   ?
;         старт (start)                 из
;        адрес(address)             из
;        чтение/запись(R/W)             из
;        подтверждение(acknowledge)     в   ?
;         данные (data)                в   ?
;        неподтверждение(NACK)         из
;         стоп (stop)                 из
;
; Параметры в стеке
; ––––––––––––––––––––
; флаг ошибки        error_flag    младшая область памяти    low mem
; младший байт данных     data
; не используется        unused
; команда             command
; адрес            address    старшая область памяти    high mem
; –––––––––––––––––
; Пример использования 
; ––––––––––––––
;     PUSH    #00h        ; место для кода ошибки
;     PUSH    #000Bh    ; поместить адрес в стек
;     PUSH    #008h        ; код команды чтения температуры батареи
;     PUSH    #00h        ; зарезервировать байт для данных (не используется)
;     PUSH    #00h        ; зарезервировать байт для данных
;     CALL    #rbp 
;     POP    R10         ; переместить данные в R10
;     ADD    #06h, SP    ; освободить место команды и адреса
;     POP    R9         ; читать из стека код ошибки
;     CMP    #00h, R9
;     JZ    error         ; ошибочное завершение – вызов обработчика ошибок
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
rbp
PUSH    SR
PUSH    R7
PUSH    R8
PUSH    R9
PUSH    R14
PUSH    R15
PUSH    R10
PUSH    R11
PUSH    R12
PUSH    R13
MOV.B 26(SP), R8     ; параметр команды
MOV.B 28(SP), R7     ; параметр адреса
CALL    #sbit         ; отправить стартовую посылку и адрес
CALL    #sendzero     ; отправить «0» для записи
CALL    #ack         ; ждём подтверждения (ACK)
CALL    #sbyte     ; отправить код команды
CALL    #ack         ; ждём подтверждения (ACK)
CALL    #rsbit         ; отправить повторяющиеся стартовую посылку и адрес
CALL    #sendone     ; отправить «1» для чтения
CALL    #ack         ; ждём подтверждения (ACK)
CALL    #rbyte         ; принять байт данных
CALL    #nack         ; отправить неподтверждение (NACK)
CALL    #pbit         ; отправить стоповую посылку
MOV.B R14, 22(SP)     ; копировать байт данных в стек
MOV.B #01h, 30(SP) ; возвращает «1» при успешном завершении
POP    R13
POP    R12
POP    R11
POP    R10
POP    R15
POP    R14
POP    R9
POP    R8
POP    R7
POP    SR
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Протокол «Читать слово» 7
; ==========================================================================
; Влияние на регистры: нет
; Влияние на память: стек, максимум 40 байт
; ––––––––––––––––––––––––––-––––––––––––––––––––––––––-––––––––––––––––––––––––
; Описание     Шаг                     Направление
; ––––––––––––––––––––––––––––––––––––––––––––––––––––-–––––––––––––––––––––––––
;         старт (start)                 из
;        адрес(address)             из
;        чтение/запись(R/W)             из
;        подтверждение(acknowledge)     в   ?
;        команда (command)            из
;        подтверждение(acknowledge)     в   ?
;         старт (start)                 из
;        адрес(address)             из
;        чтение/запись(R/W)             из
;        подтверждение(acknowledge)     в   ?
;         данные (data)                в   ?
;        подтверждение(acknowledge)     в   ?
;         данные (data)                в   ?
;        подтверждение(acknowledge)     в   ?
;         стоп (stop)                 из

; Параметры в стеке
; ––––––––––––––––––––
; флаг ошибки        error_flag    младшая область памяти    low mem
; младший байт данных     low data byte
; старший байт данных     high data byte
; команда             command
; адрес            address    старшая область памяти    high mem

; –––––––––––––––––
; Пример использования 
; ––––––––––––––
;     PUSH    #00h        ; место для кода ошибки
;     PUSH    #00Bh        ; поместить адрес в стек
;     PUSH    #008h        ; код команды “температура батареи”
;     PUSH    #00h        ; зарезервировать байт под принимаемые данные
;     PUSH    #00h        ; зарезервировать байт под принимаемые данные
;     CALL    #rwp
;     POP    R10         ; переместить данные в R10
;     POP    R11         ; переместить данные в R11
;     ADD    #04h, SP    ; освободить место, занимаемое командой и адресом
;     POP    R9         ; читать из стека код ошибки
;     CMP    #00h, R9
;     JZ    error         ; ошибочное завершение – вызов обработчика ошибок
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
rwp
PUSH    SR
PUSH    R7
PUSH    R8
PUSH    R9
PUSH    R14
PUSH    R15
PUSH    R10
PUSH    R11
PUSH    R12
PUSH    R13
MOV.B 26(SP), R8     ; параметр команды
    MOV.B 28(SP), R7     ; параметр адреса
CALL    #sbit         ; отправить стартовую посылку и адрес
CALL    #sendzero     ; отправить «0» для записи
CALL    #ack         ; ждём подтверждения (ACK)
CALL    #sbyte     ; отправить код команды
CALL    #ack         ; ждём подтверждения (ACK)
CALL    #rsbit         ; отправить повторяющиеся стартовую посылку и адрес
CALL    #sendone     ; отправить «1» для чтения
CALL    #ack         ; ждём подтверждения (ACK)
CALL    #rbyte         ; принять младший байт данных
MOV.B R14, 22(SP)     ; сохранить младший байт данных в стеке
CALL    #sack         ; ждём подтверждения (ACK)
CALL    #rbyte         ; принять старший байт данных
CALL    #nack         ; отправить неподтверждение (NACK)
CALL    #pbit         ; отправить стоповую посылку
MOV.B R14, 24(SP)     ; сохранить старший байт данных в стеке
MOV.B #01h, 30(SP) ; возвращает «1» при успешном завершении
POP    R13
POP    R12
POP    R11
POP    R10
POP    R15
POP    R14    
POP    R9
POP    R8
POP    R7
POP    SR
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Протокол «Запись блока» 8
; ==========================================================================
; Влияние на регистры: нет
; Влияние на память: стек, максимум 40 байт, блок памяти
; Описание     Шаг                     Направление
; ––––––––––––––––––––––––––––––––––––––––––––––––––––-–––––––––––––––––––––––––
;         старт (start)                 из
;        адрес(address)             из
;        чтение/запись(R/W)             из
;        подтверждение(acknowledge)     в   ?
;        команда (command)            из
;        подтверждение(acknowledge)     в   ?
;         счётчик байт (byte count)        из
;        подтверждение(acknowledge)     в   ?
;         данные (data)                из
;        подтверждение(acknowledge)     в   ?
;
;         данные (data)                в   ?
;        подтверждение(acknowledge)     в   ?
;
;        данные и ACK повторяются n раз    
;         стоп (stop)                 из

; Параметры в стеке
; ––––––––––––––––––––
; флаг ошибки        error_flag    младшая область памяти    low mem
; счётчик байт        byte count
; указатель блока        block pointer
; команда             command
; адрес            address    старшая область памяти    high mem
; –––––––––––––––––
; Пример использования 
; ––––––––––––––
;     PUSH    #00h        ; место для кода ошибки
;     PUSH    #00Bh        ; поместить адрес в стек
;     PUSH    #0020h    ; код команды “температура батареи”
;     PUSH    #00550h     ; указатель на начало блока
;     PUSH    #00h        ; зарезервировать байт под счётчик 
;     CALL    #blkw
;     POP    R10         ; переместить данные в R10
;     ADD    #06h, SP    
;     POP    R9         ; читать из стека код ошибки
;     CMP    #00h, R9
;     JZ    error         ; ошибочное завершение – вызов обработчика ошибок
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
blkw
PUSH    SR
PUSH    R7
PUSH    R8
PUSH    R9
PUSH    R14
PUSH    R15
PUSH    R10
PUSH    R11
PUSH    R12
PUSH    R13
MOV.B 26(SP), R8     ; параметр команды
MOV.B 28(SP), R7     ; параметр адреса
MOV 24(SP), R9     ; стартовый адрес блока
MOV.B #00h, R15     ; циклический байтовый счётчик
CALL    #sbit         ; отправить стартовую посылку и адрес
CALL    #sendzero     ; отправить «0» для записи
CALL    #ack         ; ждём подтверждения (ACK)
CALL    #sbyte     ; отправить код команды
CALL    #ack         ; ждём подтверждения (ACK)
MOV.B 22(SP), R8     ; копировать счётчик байт
CALL    #sbyte     ; отправить счётчик байт
CALL    #ack         ; ждём подтверждения (ACK)
blk_rep     MOV.B 0(R9), R8     ; передать данные из блока
CALL    #sbyte     ; отправить байт данных
CALL    #ack         ; ждём подтверждения (ACK)
INC    R15         ; инкремент счётчика положения блока
INC    R9         ; инкремент указателя блока
CMP    22(SP), R15     ; проверка завершения данных
JNZ    blk_rep     ; повтор до завершения
CALL    #pbit        ; отправить стоповую посылку
        MOV.B #01h, 30(SP) ; возвращает «1» при успешном завершении
POP    R13
POP    R12
POP    R11    
POP    R10
POP    R15
POP    R14
POP    R9
POP    R8
POP    R7
POP    SR
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Протокол «Чтение блока» 9
; ==========================================================================
; Влияние на регистры: нет
; Влияние на память: стек, максимум 40 байт, блок памяти
; Описание     Шаг                     Направление
; ––––––––––––––––––––––––––––––––––––––––––––––––––––-–––––––––––––––––––––––––
;         старт (start)                 из
;        адрес(address)             из
;        запись(W)                 из
;        подтверждение(acknowledge)     в   ?
;        команда (command)            из
;        подтверждение(acknowledge)     в   ?
;         старт (start)                 из
;        адрес(address)             из
;        чтение(R)                 из
;        подтверждение(acknowledge)     в   ?
;         счётчик байт (byte count)        в   ?
;        подтверждение(acknowledge)     из
;         данные (data)                в   ?
;        подтверждение(acknowledge)     из
;
;        данные и ACK повторяются n раз    
;        неподтверждение(NACK)         из
;         стоп (stop)                 из
; Параметры в стеке
; ––––––––––––––––––––
; флаг ошибки        error_flag    младшая область памяти    low mem
; счётчик байт        byte count
; указатель блока        block pointer
; команда             command
; адрес            address    старшая область памяти    high mem
; –––––––––––––––––
; Пример использования 
; ––––––––––––––
;     PUSH    #00h        ; место для кода ошибки
;     PUSH    #00Bh        ; поместить адрес в стек
;     PUSH    #0020h    ; код команды “температура батареи”
;     PUSH    #00550h     ; указатель на начало блока
;     PUSH    #00h        ; зарезервировать байт под счётчик 
;     CALL    #blkr
;     POP    R10         ; переместить счётчик  в R10
;     ADD    #06h, SP    
;     POP    R9         ; читать из стека код ошибки
;     CMP    #00h, R9
;     JZ    error         ; ошибочное завершение – вызов обработчика ошибок
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
blkr
PUSH    SR
PUSH    R7
PUSH    R8
PUSH    R9
PUSH    R14
PUSH    R15    
PUSH    R10
PUSH    R11
PUSH    R12
PUSH    R13
MOV.B #00h, R15     ; циклический байтовый счётчик
MOV.B 26(SP), R8     ; параметр команды
MOV.B 28(SP), R7     ; параметр адреса
MOV 24(SP), R9     ; стартовый адрес блока
CALL    #sbit         ; отправить стартовую посылку и адрес
CALL    #sendzero    ; отправить «0» для записи
CALL    #ack         ; ждём подтверждения (ACK)
CALL    #sbyte     ; отправить код команды
CALL    #ack         ; ждём подтверждения (ACK)
CALL    #rsbit         ; отправить повторяющиеся стартовую посылку и адрес
CALL    #sendone     ; отправить «1» для чтения
CALL    #ack         ; ждём подтверждения (ACK)
CALL    #rbyte
MOV.B R14, 22(SP)    ; поместить счётчик в стек
CALL    #sack         ; отправить подтверждение (ACK)
rblk_rep     CALL #rbyte     ; принять байт данных
MOV.B R14, 0(R9)     ; переместить данные из блока
INC    R15         ; инкремент счётчика положения блока
INC    R9         ; инкремент указателя блока
CMP 22(SP), R15     ; проверка завершения данных
JZ    blk_done     ; повтор до завершения
CALL    #sack         ; отправить подтверждение (ACK)
CMP 22(SP), R15     ; проверка завершения данных
JNZ    rblk_rep     ; повтор до завершения
blk_done     CALL     #nack         ; отправить неподтверждение (NACK)
CALL    #pbit         ; отправить стоповую посылку
MOV.B #01h, 30(SP) ; возвращает «1» при успешном завершении
POP    R13
POP    R12
POP    R11
POP    R10
POP    R15
POP    R14
POP    R9
POP    R8
POP    R7
POP    SR
RET
;****************************************************************************
; Подпрограммы нижнего уровня, общие для всех протоколов 
;****************************************************************************
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; отправка стартовой последовательности и адреса
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
sbit                     ; «отпустить» обе линии
BIC.B    #DNC, DIR
; проверка освобождения шины
MOV    #05h, R10    ; счётчик на 50 микросекунд
wait
MOV.B IN, R11     ; копировать состояние входов в R11
AND    #DNC, R11     ; маска входов
CMP    #DNC, R11     ; если линии SDA или SCL в лог. «0»то шина занята
JNZ    busy
DEC    R10         ; декремент счётчика
JNZ    wait
rsbit        BIC.B    #DNC, DIR     ; дополнительное освобождение линии с целью 
                    ; использования этой же подпрограммы для 
                    ; команды повторяющегося старта
; отправка стартовой последовательности
BIS.B    #SDA, DIR
BIS.B    #SCL, DIR
; отправка адреса 
MOV.B #07h, R13     ; счётчик на 7 бит адреса
MOV.B R7, R11     ; копировать адрес в R11
ashift         RLA.B    R11         ; сдвиг влево, при этом СЗР 7-битного адреса
; будет находиться  на 7-й позиции
MOV.B R11, R12     ; скопировать его для возможности маскирования
; без потери данных
AND.B    #080h, R12     ; маскировать все биты кроме СЗР
CMP.B #00h, R12     ; сравнить с 0
JNZ    one
CALL    #sendzero     ; отправить «1» 
JMP    zero
one         CALL    #sendone     ; отправить «0»
zero         DEC    R13         ; декремент счётчика
JNZ    ashift         ; если счётчик <7 бит, повторить сдвиг
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; подтверждение (ACK) не принято, отправить STOP и  busy
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
sbusy         CALL    #pbit         ; отправить STOP и  busy 
ADD    #02h, SP     ; удалить данные из стека, так как
; инструкция RET не использовалась
MOV.B #00h, 28(SP) ; код ошибки
POP    R13         ; восстановление регистров
POP    R12
POP    R11
POP    R10
POP    R15
POP    R14
POP    R9
POP    R8
POP    R7
POP    SR
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Обработка состояния занятости (busy)
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
busy3         ADD     #06h, SP     ; удалить лишние данные от подпрограмм
;  sendone или sendzero
busy         ADD     #02h, SP     ; удалить данные из стека, так как
; инструкция RET не использовалась
MOV.B #00h, 28(SP) ; код ошибки 
POP     R13         ; восстановить регистры
POP     R12
POP     R11    
POP     R10
POP     R15
POP     R14
POP     R9
POP     R8
POP     R7
POP     SR
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Отправить «1»
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
sendone     PUSH    R10
PUSH    R11
BIC.B    #SDA, DIR     ; установить лог. «1» на линии  SDA
BIC.B    #SCL, DIR     ; установить лог. «1» на линии  SCL
; проверка удлинения тактового сигнала (clock low extending),
; чтобы не опережать ведомое устройство
MOV.B #04h, R11     ; установить число тактов для верного времени
clkext         MOV.B IN, R10     ; проверка шины
DEC    R11
JZ     busy3         ; арбитраж – время истекло
AND.B #SCL, R10     ; проверка линии SCL
JZ    clkext
; арбитраж: убедиться, что на линии SDA действительно лог. «1», иначе приоритет
; отдаётся другому ведущему устройству
MOV.B IN, R10     ; проверка шины
AND.B #SDA, R10     ; маскировать всё, кроме SDA
JZ     busy3
BIS.B #SCL, DIR     ; освободить линию SCL
MOV.B IN, R10     ; определение повторяющейся 
; стартовой последовательности
AND.B #SDA, R10
JZ    busy3
POP    R11
POP    R10
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Отправить «0»
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
sendzero
PUSH    R10
PUSH    R11
BIS.B #SDA, DIR     ; выставить лог. «0» на линии SDA
BIC.B #SCL, DIR     ; выставить лог. «1» на линии SCL
; проверка удлинения тактового сигнала (clock low extending),
; чтобы не опережать ведомое устройство
MOV    #04h, R11     ; счётчик времени перехода SCL в «1»
clke         MOV.B IN, R10     ; проверка шины
DEC    R11
JZ    busy3         ; арбитраж – время истекло
AND.B #SCL, R10     ; проверка линии SCL
JZ    clke
BIS.B #    SCL, DIR     ; освободить линию SCL
POP    R11
POP    R10
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Ожидание подтверждения (ACK)
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
ack
BIC.B    #SDA, DIR     ; выставить лог. «1» на линии SDA
BIC.B    #SCL, DIR     ; выставить лог. «1» на линии SCL
; проверка удлинения тактового сигнала (clock low extending),
; чтобы не опережать ведомое устройство
;MOV    #008h, R11     ; счётчик на ?50 мкс
MOV    #02FFh, R11     ; удлинённый счётчик для батареи PS100Z–200
clkex         MOV.B IN, R10     ; проверка шины
DEC    R11
JZ    busy         ; арбитраж – время истекло
AND.B #SCL, R10     ; проверка линии SCL
JZ    clkex
; ожидание подтверждения (ACK) (SDA переходит в лог. «0»)
MOV    #05F6h, R11     ; счётчик таймаута для NACK
wack
MOV.B IN, R10     ; проверка шины
DEC    R11
JZ    sbusy         ; таймаут NACK–– отправить бит P и повторить попытку
AND.B #SDA, R10     ; маскировать всё, кроме SDA
JNZ    wack         ; приём ACK или ожидание таймаута
BIS.B    #SCL, DIR     ; выставить лог. «0» на линии SCL
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Отправка стоповой последовательности 
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
pbit
BIS.B    #SDA, DIR     ; выставить лог. «0» на линии SDA
BIS.B    #SCL, DIR     ; выставить лог. «0» на линии SCL
NOP
BIC.B    #SCL, DIR     ; выставить лог. «1» на линии SCL
NOP
BIC.B    #SDA, DIR     ; выставить лог. «1» на линии SDA
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Отправка байта (используются также sendzero и sendone)
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
sbyte
; отправка данных 
MOV.B #08h, R13     ; счётчик на ?50 мкс
MOV.B R8, R11     ; копировать данные в R11
dshift
MOV.B R11, R12
AND.B #080h, R12     ; маскировать все биты, кроме СЗР
CMP.B #00h, R12     ; сравнить с 0
JNZ    on
CALL    #sendzero     ; отправить «1»
JMP    zer
on         CALL    #sendone     ; отправить «0»
zer
RLA.B    R11         ; сдвиг влево, отправляемый бит в СЗР
DEC    R13         ; декремент счётчика на 8 
JNZ    dshift
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Приём байта
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
rbyte
MOV.B #08h, R12     ; счётчик на 8 бит данных 
BIC.B    #SDA, DIR     ; выставить лог. «1» на линии SDA
rrep
BIS.B    #SCL, DIR     ; выставить лог. «0» на линии SCL
BIC.B    #SCL, DIR     ; выставить лог. «1» на линии SCL
MOV    #0035h, R13     ; удлинённый счётчик для батареи PS100Z–200
; удлинение тактового сигнала
clkxtn         MOV.B IN, R10     ; проверка шины
DEC    R13
JZ    busy         ; выход по таймауту
AND.B #SCL, R10
JZ    clkxtn         ; ожидание, если SCL не «1»
MOV.B IN, R10     ; проверка шины
RLA.B    R11         ; move over for input as LSB
AND.B    #SDA, R10     ; проверка SDA
JZ    inzero
BIS.B    #01h, R11     ; установить «1» в МЗР
inzero         DEC    R12
JNZ    rrep         ; продолжение для оставшейся части байта
MOV.B R11, R14     ; копирование данных
BIS.B    #SCL, DIR     ; выставить лог. «0» на линии SCL
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Отправка неподтверждения (NACK)
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
nack
BIC.B    #SDA, DIR     ; выставить лог. «1» на линии SDA
BIS.B    #SCL, DIR     ; выставить лог. «0» на линии SCL
BIC.B    #SCL, DIR     ; выставить лог. «1» на линии SCL
; проверка удлинения тактового сигнала (clock low extending),
; чтобы не опережать ведомое устройство
; ждём установки «1» на линии SCL
clkn         MOV.B IN, R10
AND.B    #SCL, R10     ; проверка линии SCL
JZ    clkn
BIS.B    #SCL, DIR     ; «отпустить» SCL
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Отправка подтверждения (ACK)
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
sack                     ; ждём, пока ведомый «отпустит» линию SDA
MOV    #000Fh, R11     ; счётчик на ?50 мкс
swaita         MOV.B IN, R10     ; проверка шины 
DEC    R11
JZ    busy
AND.B #SDA, R10     ; проверка SCL
JZ    swaita
BIS.B    #SDA, DIR     ; перевести SDA в «0»
BIC.B    #SCL, DIR     ; перевести SCL в «1»
MOV    #000Fh, R11     ; счётчик на ?50 мкс
swait         MOV.B IN, R10     ; проверка шины
DEC    R11
JZ    busy    
AND.B #SCL, R10     ; проверка SCL
JZ    swait
BIS.B    #SCL, DIR     ; перевести SCL в «0»
BIC.B    #SDA, DIR     ; «отпустить» SDA
RET
;––– очистка ЖКИ
show_clr
MOV    #15, r5     ; очистка дисплейной памяти
show_clr1
MOV.b #0, LCD1–1(r5)
DEC    r5
JNZ    show_clr1
RET
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Определения для ЖКИ
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
LCD_TYPE
;–––ЖКИ модуля STK/EVK
a         .equ    01h
b         .equ    02h
c         .equ    10h
d         .equ    04h
e         .equ    80h
f         .equ    20h
g         .equ    08h
h         .equ    40h
;––– Определения символов
LCD_Tab     .byte    a+b+c+d+e+f     ; отображает”0”
.byte    b+c         ; отображает”1”
.byte    a+b+d+e+g     ; отображает”2”
.byte    a+b+c+d+g     ; отображает”3”
.byte    b+c+f+g     ; отображает”4”
.byte     a+c+d+f+g     ; отображает”5”
.byte    a+c+d+e+f+g     ; отображает”6”
.byte    a+b+c         ; отображает”7”
.byte    a+b+c+d+e+f+g ; отображает”8”
.byte    a+b+c+d+f+g ; отображает”9”
.byte    0         ; отображает ”:” пустой
.byte    g         ; отображает”;” –
.byte    a+d+e+f     ; отображает”<” [
.byte    d+g         ; отображает”=”
.byte    a+b+c+d     ; отображает”>” ]
.byte    a+b+e+g     ; отображает”?”
.byte    a+b+d+e+f+g ; отображает”@”
.byte    a+b+c+e+f+g ; отображает”A”
.byte    c+d+e+f+g     ; отображает”B” b
.byte    a+d+e+f     ; отображает”C”
.byte    b+c+d+e+g     ; отображает”D” d
.byte    a+d+e+f+g     ; отображает”E”
.byte    a+e+f+g     ; отображает”F”
.byte    a+b+c+d+f+g ; отображает”G”
.byte    b+c+e+f+g     ; отображает”H”
.byte    b+c         ; отображает”I”
.byte    b+c+d+e     ; отображает”J”
.byte    0         ; отображает”K”
.byte    d+e+f         ; отображает”L”
.byte    a+b+c+e+f     ; отображает”M”
.byte    c+e+g         ; отображает”N” n
.byte    c+d+e+g     ; отображает”O” o
.byte    a+b+e+f+g     ; отображает”P”
.byte    0         ; отображает”Q”
.byte    e+g         ; отображает”R” r
.byte    a+c+d+f+g     ; отображает”S”
.byte    d+e+f+g     ; отображает”T” t
.byte    c+d+e         ; отображает”U” u
.byte     0         ; отображает”V”
.byte    0         ; отображает”W”
.byte    0         ; отображает”X”
.byte    b+c+d+f+g     ; отображает”Y”
.byte    a+b+d+e+g     ; отображает”Z” 2
LCD_Tab_End
.even
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Вектора прерываний 
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; .sect ”Int_Vect”,0FFFFh–1 ; без программы монитора
; .word RESET     ; POR, внеш. Reset, Watchdog
; .end
.sect ”Int_Vect”,05FFh–1 ; с программой монитора
.word RESET         ; POR, внеш. Reset, Watchdog
.end

Приложение C Программа ведомого устройства шины SMBus

;****************************************************************************
; Программа ведомого устройства шины SMBus
;****************************************************************************
USER_END         .set     0FFFFh
Device         .set     325
;––– Определения управляющих регистров
SRE         .equ     0h
IE1         .equ     0h
IE2         .equ     01h
IFG1         .equ     02h
IFG2         .equ     03h
WDTCTL     .equ     0120h
WDTHold     .equ     80h
WDT_wrkey     .equ     05A00h
CPUOFF     .set     10h
OSCOFF     .set     20h
;Порт PORT 0
P0IE         .equ     015h
P0DIR     .equ     012h
P0IN         .equ     010h
P0OUT     .equ     011h
P0IES         .equ     014h
P0IFG         .equ     013h
;Порт  port 2
P2IN         .equ     028h
P2OUT     .equ     029h
P2IE         .equ     02Dh
P2SEL     .equ     02Eh
P2DIR     .equ     02Ah
LCD1         .equ     031h
LCDM         .equ     030h
OUT         .equ     P0OUT
IN         .equ     P0IN
DIR         .equ     P0DIR
SDA         .equ     010h
SCL         .equ     020h
DNC         .equ     030h
; Расположение таблицы
Table         .equ     0300h
;****************************************************************************
; Reset : инициализация процессора
;****************************************************************************
.sect ”onreset”,0FFFEh
.word     INIT
.sect ”intv”, 0FFE0h
.word     rbp
.sect ”MAIN”,0C000h
INIT
.if Device = 325
MOV #03C0h, SP
.endif
.if Device = 337
MOV #05D0h, SP
.endif
MOV #(WDTHold+WDT_wrkey),&WDTCTL 
; Остановить сторожевой таймер Watchdog Timer
; Инициализация порта port2
BIC.B #DNC, DIR     ; Биты 1 и 0 - входы
BIC.B #DNC, OUT     ; установить лог. «1» на линиях SDA и SCL
BIS.B #SDA, P0IE     ; разрешить прерывания по P0.4
BIS.B #SDA, P0IES     ; прерывание по спаду на P0.4
RESET
nready     ; шина не находится в состоянии готовности / нет стартовой посылки
waddr         ; возврат сюда, если неверный адрес устройства
MOV.B #000h, error     ; сброс флага ошибки 
MOV.B #055h, address 
; адрес = 55h
MOV.B #09h, data     ; данные = 09h
EINT         ; общее разрешение прерываний 
;****************************************************************************
; Начало пользовательской программы
;****************************************************************************
repeat
JMP repeat         ; ожидание прерывания 
;****************************************************************************
; Завершение пользовательской программы
;****************************************************************************
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; приём байта (здесь обрабатывается прерывание)
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
rbp
;PUSH R11         ; если известно, что стартовая посылка длительная,
; можно добавить эти строки
;PUSH R12
;PUSH R13
;PUSH R14
BIC.B     #SDA, P0IFG ; очистить флаг прерывания 
;****************************************************************************
; проверка стартовой последовательности 
;****************************************************************************
wait2         MOV.B IN, R11     ; копировать состояние входов в R11
DEC     R9
JZ     done
AND     #DNC, R11     ; маскировать все биты, кроме входов
CMP     #SCL, R11     ; убедиться, что на линии SDA лог. «0»
; а на SCL лог. «1»
JNZ     wait2         ; если нет - ожидаем
wait3         MOV.B IN, R11     ; копировать состояние входов в R11
DEC     R9
JZ     done
AND     #DNC, R11     ; маскировать все биты, кроме входов
JNZ     wait3         ; если нет - ожидаем
;****************************************************************************
; Стартовая последовательность получена
;****************************************************************************
MOV     #007h, R13     ; счётчик на 7 адресных бит
MOV     #0000h, R12     ; регистр для сохранения адреса
taddr         MOV.B IN, R14     ; убедиться, что на линии SCL лог. «0»
DEC     R9
JZ     done
AND     #SCL, R14
JNZ     taddr
addr         MOV.B IN, R14     ; чтение порта 
DEC     R9
JZ     done
MOV.B R14, R11     ; копировать данные 
AND     #SCL, R14     ; маскировать все биты, кроме SCL
JZ     addr         ; ждём лог. «1» на SCL
AND     #SDA, R11     ; маскировать все биты, кроме SDA
JZ     szero         ; если «0» - просто сдвиг
RLA.B R12         ; сдвиг влево 
BIS.B     #0001h, R12     ; если «1» установить «1» в МЗР и сдвиг
JMP     sone
szero
RLA.B R12         ; арифметический сдвиг влево ? 0
sone         DEC     R13         ; декремент счётчика 
JNZ     taddr         ; повтор, если менее 7 бит
MOV.B address, R13 ; копировать адрес устройства в R13
CMP.B R13, R12     ; и сравнить его с принятым адресом
JNZ     waddr         ; переход, если адрес неверный
;****************************************************************************
; адрес правильный, продолжаем
;****************************************************************************
; чтение бита R/W (чтение/запись)
rwait2         MOV.B IN, R11     ; ждём лог. «0» на SCL
DEC     R9
JZ     done
AND.B #SCL, R11     ; маскировать все биты, кроме SCL
JNZ     rwait2
rwait         MOV.B IN, R11     ; ждём лог. «1» на SCL
DEC     R9
JZ     done
AND.B #SCL, R11     ; маскировать все биты, кроме SCL
JZ     rwait
MOV.B IN, R11     ; копировать данные из порта
AND.B #SDA, R11     ; маскировать все биты, кроме SDA
JNZ     done         ; 0 если запись, переход, если 1 (чтение)
;****************************************************************************
; Отправить бит подтверждения (ACK)
;****************************************************************************
rwait3         MOV.B IN, R11     ; ждём лог. «0» на SCL
DEC     R9
JZ     done
AND.B #SCL, R11      ; маскировать все биты, кроме SCL
JNZ     rwait3
BIS.B #SDA, DIR     ; перевести линию SDA в лог. «0»
rwait4         MOV.B IN, R11     ; ждём лог. «1» на SCL
DEC     R9
JZ     done
AND.B #SCL, R11     ; маскировать все биты, кроме SCL
JZ     rwait4
rwait5         DEC     R9
JZ     done
MOV.B IN, R11     ; ждём лог. «0» на SCL
AND.B #SCL, R11     ; маскировать все биты, кроме SCL
JNZ     rwait5
BIC.B     #SDA, DIR     ; «отпустить» линию SDA
;****************************************************************************
; готов принять байт
;****************************************************************************
MOV     #008h, R13     ; счётчик на 8 бит данных 
MOV     #0000h, R12     ; регистр для сохранения адреса
tdat         MOV.B IN, R14     ; убедиться, что на линии SCL лог. «0»
DEC     R9
JZ     done
AND     #SCL, R14
JNZ     tdat
dat         MOV.B IN, R14     ; читаем данные из порта 
MOV.B R14, R11     ; копируем данные 
DEC     R9
JZ     done    
AND     #SCL, R14     ; маскировать все биты, кроме SCL
JZ     dat         ; ждём лог. «1» на SCL
AND     #SDA, R11     ; маскировать все биты, кроме SDA
JZ     szeroc     ; если «0» - просто сдвиг
RLA.B     R12
BIS.B     #0001h, R12     ; если «1» установить «1» в МЗР и сдвиг
JMP     szerob
szeroc     RLA.B     R12         ; арифметический сдвиг влево
szerob
DEC     R13         ; декремент счётчика
JNZ     tdat
MOV.B R12, data     ; копируем в ОЗУ
;****************************************************************************
; Отправить бит подтверждения (ACK)
;****************************************************************************
rwait6         MOV.B IN, R11     ; ждём лог. «0» на SCL
DEC     R9
JZ     done
AND.B #SCL, R11     ; маскировать все биты, кроме SCL
JNZ     rwait6
BIS.B     #SDA, DIR     ; перевести линию SDA в лог. «0»
rwait7         MOV.B IN, R11     ; ждём лог. «1» на SCL
DEC     R9
JZ     done
AND.B #SCL, R11     ; маскировать все биты, кроме SCL
JZ     rwait7
rwait8         MOV.B IN, R11     ; ждём лог. «0» на SCL
DEC     R9
JZ     done
AND.B #SCL, R11     ; маскировать все биты, кроме SCL
JNZ     rwait8
BIC.B     #SDA, DIR     ; «отпустить» линию SDA
done
;POP R14         ; если известно, что стартовая посылка длительная,
; можно добавить эти строки
;POP R13
;POP R12
;POP R11
        MOV #0FFh, R9
        RETI
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; переменные 
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
address       .equ     0248h         ; адрес устройства 
data          .equ     0242h         ; отправляемые данные 
datin         .equ     0244h         ; принимаемые данные 
error         .equ     0246h         ; флаг ошибки 

Приложение E Содержание файла ASCII.txt
@B500
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
B7 12 8F 1F 3A 3D BD 13 BF 3F 00 00 00 00 00 00
00 BB BC A5 9E AD A9 3F BA 12 96 00 A4 B3 98 9C
AB 00 88 3D AC 94 00 00 00 3E 8F 00 00 00 00 00
00 BB BC A5 9E AD A9 3F BA 12 96 00 A4 B3 98 9C
AB 00 88 3D AC 94 00 00 00 3E 8F 00
q

Популярный сайт знакомств общения maybe.ru