Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Описание2.doc
Скачиваний:
15
Добавлен:
13.03.2016
Размер:
22.6 Mб
Скачать

7. Разработка програмного обеспечения

Программное обеспечение реализовывалось по следующим алгоритмам:

Начало

Нет

Конец

и алгоритм формирования Y3 и Y2:

Да

Нет

Формирование Y3

Листинг программы:

bseg ; объявляем сегмент с побитовым доступом для флагов I2C и других

NoAck : dbit 1

BusFault : dbit 1

I2CBusy : dbit 1

X1 : dbit 1

X2 : dbit 1

X3 : dbit 1

X4 : dbit 1

dseg at 30h

sum : ds 3

N5 : ds 20

N6 : ds 20

N7 : ds 2

Q2 : ds 3

Q4 : ds 2

Q0 : ds 2

K : ds 1

A0 : ds 2

A1 : ds 1

BitCnt : ds 1 ; Счетчик битов для I2C

ByteCnt : ds 1 ; Счетчик байтов для I2C

SlvAdr : ds 1 ; Адрес ведомого

tout : ds 3 ; таймаут

XmtDat : ds 8 ; Буфер передачи I2C, 8 байт

RcvDat : ds 8 ; Буфер приема I2C, 8 байт

N equ 10

KEYB_ADDR equ 01110100b

ADC_ADDR equ 01000010b

cseg

jmp start

org 3h

jmp int1_alarm

org 13h

jmp int2_power

org 23h

jmp int3_keyb

org 40h

constQ0: dw 7FFh ; константа Q0

constK: db 24 ; K

constA0: dw 1F4h ; A0

constA1: db 4 ; A1

stack equ 0C8h ; глубина стека от 200 до 255 байт - 55 байт

CONVST bit P1.0 ; сигнал запуска АЦП

HBEN bit P1.2 ; разрешение загрузки старшего байта в ЦАП

LDAC bit P1.3 ; обновление регистров ЦАП

Y1 bit P1.4 ; управляющий сигнал

CS1 bit P1.5 ; управление контроллером дисплея

CE0 bit P1.6 ; управление таймером КР580ВИ53

ALM bit P1.7 ; аварийная сигнализация

SCLpin bit P3.0 ; синхронизация I2C

SDApin bit P3.1 ; данные I2C

CE1 bit P3.4 ; управление таймером КР580ВИ53

WDI bit P3.5 ; управление сторожевым таймером

start:

mov SP,#stack-1

mov IE,#7Fh ; запретим прерывания

mov P1,#10011100b

mov P3,#11000011b

setb WDI ; сбросим watchdog

nop

clr WDI

;//////////////////////////////

; инициализация Т2 как источника внешнего прерывания

mov 0C9h,#00000000B ; перезапускаемый режим (0C9h - адрес T2MOD)

mov 0C8h,#01001000B ; Режим таймера Т2. Счетчик, счет от внешнего входа (0C8h - адрес T2CON)

mov 0CDh,#0FFH ; Запись значения в таймер Т2 (0CDh - адрес TH2)

mov 0CCh,#0FFH ; Запись значения для 16 разрядного счета (0CCh - адрес TH2)

;//////////////////////////////

; инициализируем АЦП

mov XmtDat,#00000010b ; адрес РУС

mov XmtDat+1,#01010000b; управляющее слово

mov SlvAdr,#ADC_ADDR ; загрузим адрес с запросом записи - последний бит "0"

mov R0,#XmtDat ;

mov ByteCnt,#2 ;

acall SendData ;

; теперь необходимо вернуть указатель на регистр результата

mov XmtDat,#00000000b ; адрес регистра результата

mov SlvAdr,#01000010b ; загрузим адрес с запросом записи - последний бит "0"

mov R0,#XmtDat ;

mov ByteCnt,#1 ;

acall SendData ;

;/////////////////////////////

; инициализируем контроллер клавиатуры

mov XmtDat,#00000001b ; адрес РУС

mov XmtDat+1,#00000000b; управляющее слово для 0х01

mov XmtDat+2,#00000000b; управляющее слово для 0х02 - автоувеличение адреса

mov XmtDat+3,#10100000b; управляющее слово для 0х03 - автоувеличение адреса

mov XmtDat+4,#10000000b; управляющее слово для 0х04 - автоувеличение адреса

mov SlvAdr,#KEYB_ADDR ; загрузим адрес с запросом записи - последний бит "0"

mov R0,#XmtDat ;

mov ByteCnt,#5 ;

acall SendData ;

; теперь необходимо вернуть указатель на регистр FIFO

mov XmtDat,#00000000b ; адрес регистра FIFO

mov SlvAdr,#01110100b ; загрузим адрес с запросом записи - последний бит "0"

mov R0,#XmtDat ;

mov ByteCnt,#1 ;

acall SendData ;

;///////////////////////////////////

; загрузим константы

mov DPTR,#constQ0 ; константа Q0

mov A,#00h ; старший байт

movc A,@A+DPTR ;

mov Q0,A ; старший байт

mov A,#01h ; младший байт

movc A,@A+DPTR

mov Q0+1,A ; младший байт

mov DPTR,#constK ; уставка K

mov A,#00h ;

movc A,@A+DPTR ;

mov K,A ;

mov DPTR,#constA0 ; константа A0

mov A,#00h ; старший байт

movc A,@A+DPTR ;

mov A0,A ; старший байт

mov A,#01h ; младший байт

movc A,@A+DPTR

mov A0+1,A ; младший байт

mov DPTR,#constA1 ; константа A1

mov A,#00h ;

movc A,@A+DPTR ;

mov A1,A

;////////////////////////////////////

mov IE,#0BFh ; разрешим прерывания

MAIN_CYCLE:

mov DPTR,#0C000h

movx A,@DPTR ;введем X1 - X4

mov DPTR,#0D000h

movx @DPTR,A ;выведем X1 - X4

acall CALC_Q1 ; посчитаем Y1

jnc no_Y1 ; проверяем, надо ли выводить Y1

clr Y1

acall Y1_DELAY ; задержка 90 мс

setb Y1

no_Y1:

; введем Х5, Х6, Х7

setb Y1

acall AINPUT

acall CALC_Q2

acall Y2_OR_Y3

acall CALC_Q4

acall OUTP_Y4

acall IND

;DELAY

setb WDI ; сбросим watchdog

nop

clr WDI

mov R7,#6

MAIN_DELAY1:

mov TMOD,#00000001b ; режим таймера 0 - счетчик

mov TH0,#HIGH(65536-536)

mov TL0,#LOW(65536-536)

setb TR0 ; запустим таймер

MAIN_DELAY: jnb TF0,MAIN_DELAY ; подождали 65 мс

clr TF0

clr TR0

djnz R7, MAIN_DELAY1

jmp MAIN_CYCLE

;////////////////////////////////

; рассчет Q1

CALC_Q1:

rrc A ; введем значение X1

mov X1,C

rrc A ; выдвинем второй бит и

orl C,X1 ; сделаем OR с первым

mov X1,C ; сохраним результат

rrc A ; выдвинем третий бит и

orl C,X1 ; сделаем OR с предыдущим

mov X1,C ; сохраним результат

rrc A ; выдвинем четвертый бит и

orl C,X1 ; сделаем OR с предыдущим

; конец, результат 0 или 1 образовался во флаге С

ret

;////////////////////////////////

; задержка для Y1

Y1_DELAY:

mov TMOD,#00000001b ; режим таймера 0 - счетчик

mov TH0,#HIGH(65536-60000)

mov TL0,#LOW(65536-60000)

setb TR0 ; запустим таймер

Y1_DELAY_M1:

jnb TF0,Y1_DELAY_M1 ; подождали 60 мс, надо еще 30

clr TF0

clr TR0

mov TH0,#HIGH(65536-30000)

mov TL0,#LOW(65536-30000)

setb TR0 ; запустим таймер

Y1_DELAY_M2:

jnb TF0,Y1_DELAY_M2 ; подождали еще 30 мс

clr TF0

clr TR0

ret

;/////////////////////////////////

AINPUT:

mov DPTR,#8000h ; выбор канала мультиплексора

mov A,#00h

movx @DPTR,A ; выставим номер канала

nop ; подождем

mov R1,#N5 ; адрес первого байто массива N5

mov R7,#N ; в массиве 10 элементов

AINPUT_CYCLE_N5:

setb CONVST ; включение АЦП

nop ; ожидание перехода АЦП из спящего в нормальный режим

nop

clr CONVST ; захват сигнала и запуск конвертации на АЦП

mov SlvAdr,#ADC_ADDR ; загрузим адрес с запросом записи - последний бит "0"

mov R0,#RcvDat ;

mov ByteCnt,#2 ;

acall RcvData ; так как процедура чтения сама увеличивает адрес на 1, то сама сформирует адрес с запросом на чтение

dec R0

mov A,#01h

anl A,@R0 ; уберем из старшего байта старшие 4 бита

mov @R1,A ; запишем старший байт элемента массива N5

inc R0 ; адрес младшего байта из АЦП

inc R1 ; адрес следующего байта массива N5

mov A,@R0 ; младший байт из АЦП

mov @R1,A ; младший байт элемента массива N5

inc R1 ; адрес следующего элемента массива N5

djnz R7,AINPUT_CYCLE_N5

mov R1,#N6

mov R7,#N

mov DPTR,#8001h ; выбор канала мультиплексора

mov A,#00h

movx @DPTR,A ; выставим номер канала

nop ; подождем

AINPUT_CYCLE_N6:

setb CONVST ; включение АЦП

nop ; ожидание перехода АЦП из спящего в нормальный режим

nop

clr CONVST ; захват сигнала и запуск конвертации на АЦП

mov SlvAdr,#ADC_ADDR ; загрузим адрес с запросом записи - последний бит "0"

mov R0,#RcvDat ;

mov ByteCnt,#2 ;

acall RcvData ; так как процедура чтения сама увеличивает адрес на 1, то сама сформирует адрес с запросом на чтение

dec R0

mov A,#01h

anl A,@R0 ; уберем из старшего байта старшие 4 бита

mov @R1,A ; запишем старший байт элемента массива N5

inc R0 ; адрес младшего байта из АЦП

inc R1 ; адрес следующего байта массива N5

mov A,@R0 ; младший байт из АЦП

mov @R1,A ; младший байт элемента массива N5

inc R1 ; адрес следующего элемента массива N5

djnz R7,AINPUT_CYCLE_N6

mov DPTR,#8002h ; выбор канала мультиплексора

mov A,#00h

movx @DPTR,A ; выставим номер канала

nop ; подождем

setb CONVST ; включение АЦП

nop ; ожидание перехода АЦП из спящего в нормальный режим

nop

clr CONVST ; захват сигнала и запуск конвертации на АЦП

mov SlvAdr,#ADC_ADDR ; загрузим адрес с запросом записи - последний бит "0"

mov R0,#RcvDat ;

mov ByteCnt,#2 ;

acall RcvData ; так как процедура чтения сама увеличивает адрес на 1, то сама сформирует адрес с запросом на чтение

dec R0

mov A,#01h

anl A,@R0 ; уберем из старшего байта старшие 4 бита

mov R1,#N7 ; адрес N7

mov @R1,A ; запишем старший байт N7

inc R0

inc R1

mov A,@R0 ; младший байт из АЦП

mov @R1,A ; запишем младший байт N7

ret

;//////////////////////////////////////

CALC_Q2:

mov R7,#N ; записываем счетчик элементов в массиве Q2

mov R0,#N5; начальный адрес массива N5

mov R1,#N6; начальный адрес массива N6

mov sum+2,#00h ; обнуляем старший байт суммы Qi

mov Q2+2,#00h ; обнуляем старший байт суммы массива Q2

CALC_Q2_cycle:

mov sum,#00h ; обнуление буфера промежуточных сумм

mov sum+1,#00h ;

mov sum+2,#00h ;

mov A,@R0 ; получение старшего байта

rrc A ; сдвиг вправо старшего байта элемента массива N5

mov R5,A ; запись старшего байта элемента массива N5 в R1

inc R0 ; увеличение адреса для доступа к младшему байту массива N5

mov A,@R0 ; получение младшего байта элемента массива N5

rrc A ; сдвиг вправо младшего байта массива N5, в результате имеем

mov R4,A ; поделенный на 2 элемент массива N5

clr C ;

inc R0 ; увеличение индекса для доступа к след. элементам массива

mov A,@R1 ; получение старшего байта элемента массива N6

mov R3,A ; запись старшего байта элемента массива N6 в R3

inc R1 ; увеличение адреса для доступа к младшему байту массива N6

mov A,@R1 ; получение младшего байта элемента массива N6

mov R2,A ; запись младшего байта элемента массива N6 в R2

inc R1 ; увеличение индекса для доступа к след. элементам массива

; подсуммирование К

mov A,R4 ; младший байт N5/2

add A,#K ; подсуммирование К

mov R4,A ;

mov A,R5 ; старший байт N5/2

addc A,#0 ; учет переполнения

mov R5,A ;

mov A,R4 ; младший байт N5/2

add A,R2 ; сложение с младшим байтом N6

mov sum,A ; запись младшего байта промежуточной суммы

mov A,R5 ; старший байт N5/2

addc A,R3 ; сложение со старшим байтом N6

mov sum+1,A ; запись среднего байта промежуточной суммы

jnc CALC_Q2_m11 ;

inc sum+2 ; учет переполнения

CALC_Q2_m11: ;

mov A,R0

push ACC

mov A,R1

push ACC

; сложение Q и текущей суммы элементов

mov R0,#Q2 ; адрес Q2

mov R1,#sum ; адрес sum

mov R3,#3 ; количество байтов Q2

clr C ;

CALC_Q2_addm: ;

mov A,@R0 ; запись байта Q2

addc A,@R1 ; сложение с байтом sum

mov @R0,A ; запоминание байто суммы

inc R0 ; адрес следующего байта Q2

inc R1 ; адрес следующего байта sum

djnz R3,CALC_Q2_addm ; счет количества байтов

pop ACC

mov R1,ACC

pop ACC

mov R0,ACC

djnz R7,CALC_Q2_cycle ; счет количества элементов массива

; деление суммы Q2 на N

mov R4,Q2+2 ; старший байт суммы Q2

mov R3,Q2+1 ; средний байт суммы Q2

mov R2,Q2 ; младший байт суммы Q2

mov R0,#N ; делитель

mov A,R4 ; старший байт суммы Q2

mov B,R0 ; делитель

div AB ;

mov R4,A ; получение старшего байта частного

mov R5,B ; текущий остаток

;

mov B,R0 ; делитель

mov R1,#16 ; количетво разрядов делимого

CALC_Q2_dwb3: ;

clr C ;

mov A,R2 ;

rlc A ; сдвиг влево младших разрядов частного

mov R2,A ;

mov A,R3 ;

rlc A ; сдвиг влево старших разрядов частного

mov R3,A ;

mov A,R5 ;

rlc A ; сдвиг влево текущего остатка

cjne A,B,CALC_Q2_dwb1 ; сравнение текущего остатка с делителем

CALC_Q2_dwb1: ;

jc CALC_Q2_dwb2 ; переход, если остаток меньше делителя

subb A,B ; вычитание делителя из текущего остатка

inc R2 ; запись 1 в очередной разряд частного

CALC_Q2_dwb2: ;

mov R5,A ; сохранение остатка

djnz R1,CALC_Q2_dwb3 ; повторить 16 раз

mov Q2+2,R2 ; запишем младший байт суммы Q2

mov Q2+1,R3 ; запишем средний байт суммы Q2

mov Q2,R4 ; запишем старший байт суммы Q2

ret

;///////////////////////////////

Y2_OR_Y3:

; сравним вычитанием Q2-Q0

clr C ; Вычитание осуществляем с заемом.

mov A,Q2+2 ; младший байт Q2

subb A,Q0+1 ; вычитаем младший байт Q0

mov A,Q2+1 ; средний байт Q2

subb A,Q0 ; вычитаем старший байт Q0

mov A,Q2 ; старший байт Q2

subb A,0 ; проверка, был ли заем

mov C,ACC.7 ; по результам вычитания анализируем получившееся значение на знак.

jc CREATE_Y2 ; если C=1 (Q2<Q0), переход на метку

CREATE_Y3: ; если Q2>Q0, формируем Y3

mov DPTR,#0A003h ; запись управляющего слова в РУС канала 2

mov A,#10110110b ; канал 2, тип - двоичный счетчик, режим 3 (делитель частоты), режим загрузки младший, затем старший

movx @DPTR,A ; выведем слово

nop

mov DPTR,#0A002h ; загрузим канал 2

mov A,#0F4h ; данные для загрузки - младший байт (для периода 1 мс при периоде CLК 2 мкс загрузим 500 или 1F4h)

movx @DPTR,A ; выведем данные

nop

mov A,#01h ; старший байт

movx @DPTR,A ; выведем данные

nop

mov DPTR,#0A003h ; запись управляющего слова в РУС канала 1

mov A,#01110010b ; канал 1, тип - двоичный счетчик, режим 1 (ждущий мультивибратор), режим загрузки младший, затем старший

movx @DPTR,A ; выведем данные

nop

mov DPTR,#0A001h ; загрузим канал 1

mov A,#30h ; данные для загрузки - младший байт (для формирования импульса разрешения счета каналу 2 на 60 мс, при периоде CLK 2 мкс загрузим 30000 или 7530h)

movx @DPTR,A ; выведем данные

nop

mov A,#75h ; старший байт

movx @DPTR,A ; выведем данные

nop

setb CE1 ; разрешим счет каналу 1

nop

clr CE1

ret

CREATE_Y2:

mov DPTR,#0A003h ; запись управляющего слова в РУС канала 0

mov A,#00110010B ; канал 0, тип - двоичный счетчик, режим 1 (ждущий мультивибратор), режим загрузки младший, затем старший

movx @DPTR,A ; выведем слово

nop ; подождем

mov DPTR,#0A000h ; загрузка канала 0

mov A,#98h ; данные для загрузки - младший байт (для 30 мс при периоде 2 мкс загрузим 15000 или 3А98h)

movx @DPTR,A ; выведем данные

mov A,#0H ; старший байт

movx @DPTR,A ; выведем данные

setb CE0

nop

clr CE0

ret

;///////////////////////////////

CALC_Q4:

mov A,Q4

clr C

mov A,N7 ; получение старшего байта N7

rrc A ; сдвиг вправо старшего байта N7

mov R3,A ; запись старшего байта N7 в R3

mov A,N7+1 ; получение младшего байта N7

rrc A ; сдвиг вправо младшего байта массива N5, в результате имеем

mov R2,A ; поделенный на 2 элемент N7

clr C

mov A,R3 ; получение старшего байта N7

rrc A ; сдвиг вправо старшего байта N7

mov R3,A ; запись старшего байта N7 в R3

mov A,R2 ; получение младшего байта N7

rrc A ; сдвиг вправо младшего байта массива N5, в результате имеем

mov R2,A ; поделенный на 2 элемент N7

; поделили, теперь прибавим А0

clr C

mov A,R2 ; младший байт N7

add A,A0 ; подсуммирование К

mov R2,A ;

mov A,R3 ; старший байт N7

addc A,A0+1 ;

mov R3,A ;

mov Q4+1,R2 ; запишем Q4

mov Q4,R3

ret

;///////////////////////////////

OUTP_Y4:

mov DPTR,#9000h ; адрес ЦАП

mov A,Q4+1 ; младший байт Q4

movx @DPTR,A ; выведем

nop ; подожем

setb HBEN ; разрешение загрузки старшего байта

mov A,Q4 ; старший байт

movx @DPTR,A ; вывод

nop

clr HBEN ; сбросим HBEN

clr LDAC ; обновим регистр ЦАП

nop

setb LDAC ; сбросим LDAC

ret

;///////////////////////////////

IND:

mov R3,Q4 ; старший байт 4

mov R2,Q4+1 ; младший байт

mov R0,#10 ; делитель

mov R7,#4 ; 4 знакоместа

mov DPTR,#0B000h ; выберем первое знакоместо

IND_CYCLE:

call DIV_LED

movx @DPTR,A ; выведем очередной разряд Q4

setb CS1 ; запишем в контроллер

nop

clr CS1

inc DPTR

djnz R7,IND_CYCLE

ret

;///////////////////////////////

DIV_LED: ; в R3, R2 делимое и результат, в R0 делитель, в А - остаток.

mov A,R3 ; старший байт делимого

mov B,R0 ; делитель

div AB

mov R3,A ; старший байт частного

mov A,B ; текущий остаток

mov B,R0 ; делитель

mov R1,#8 ; количество разрядов остатка

DIV_LED_dwb3:

clr C ; очистим С

xch A,R2

rlc A ; сдвиг младших частного

xch A,R2

rlc A ; сдвиг остатка

cjne A,B,DIV_LED_dwb1 ; сравнение остатка с делителем

DIV_LED_dwb1:

jc DIV_LED_dwb2 ; переход, если остаток меньше делителя

subb A,B ; вычитание делителя из текущего остатка

inc R2 ; запись 1 в очередной разряд частного

DIV_LED_dwb2:

djnz R1,DIV_LED_dwb3 ; повторить 8 раз

ret

;//////////////////////////////////////////

ALM_DELAY:

mov R7,#0C7h ; задержка примерно на 1 мс

ALM_DELAY1:

nop

nop

nop

djnz R7,ALM_DELAY1

RET

ret

;///////////////прерывания///////////////////

int1_alarm:

mov DPTR,#0C000h

movx A,@DPTR ;введем X1 - X4

mov DPTR,#0D000h

movx @DPTR,A ;выведем X1 - X4

call IND

INT1_LOOP:

setb ALM ; звуковая сигнализация 500 Гц

acall ALM_DELAY;

clr ALM

acall ALM_DELAY

jmp INT1_LOOP

reti

;///////////////////////////////////

int2_power:

mov DPTR,#1000h

mov A,#0FFh

movx @DPTR,A

mov R0, #0FFh

INT2_LOOP:

inc DPTR

mov A,@R0

movx @DPTR,A

djnz R0,INT2_LOOP

reti

;///////////////////////////////////////////

int3_keyb:

; не реализовано, т.к. не указано в задании

reti

;///////////прерывания закончились////////////////////

; Процедуры для работы с I2С

BitDly: ; задержка на 5 мкс (2 на call, 2 на ret, 1 на nop)

nop

ret

;/////////////////////////////////

SCLHigh: ; установка SCL в 1

setb SCLPin ; установить

jnb SCLPin,$ ; подождать, пока не установится в 1

ret

;///////////////////////////////////

SendStop: ; посылка stop условия и освобождение шины

clr SDAPin ; установка SDA в 0

call SCLHigh ; установка SCL в 1

call BitDly ; задержка

setb SDAPin ; посылка stop условия

call BitDly ; задержка

clr I2CBusy ; шина свободна

ret

;//////////////////////////////////

SendByte: ; процедура посылки байта, байт для посылки в Асс

mov BitCnt,#8 ;Set bit count.

SBLoop:

rlc A ; выдвинем 1 бит в С

mov SDAPin,C ; выставим бит на шине

call SCLHigh ; импульс синхронизации

call BitDly ; задержка

clr SCLPin ; конец импульса

call BitDly

djnz BitCnt,SBloop ; повторить для 8 бит

setb SDAPin ; освободим линию для приема подтвержения

call SCLHigh ; SCL для подтверждения

call BitDly

jnb SDAPin,SBEX ; получено ли подтверждение

setb NoAck ; если не получено, фиксируем

SBEX:

clr SCLPin ; завершение приема подтверждения

call BitDly

ret

;//////////////////////////////////////

GoMaster: ; процедура посылки старт-условия и адреса ведомого I2C устройства

; адрес ведомого в переменной SlvAdr

setb I2CBusy ; займем шину

clr NoAck ; очистим флаг подтверждения

clr BusFault ; и флаг ошибки

jnb SCLPin,Fault ; проверка, свободна ли шина

jnb SDAPin,Fault

clr SDAPin ; начало посылки старт-условия (SCL в 1, SDA 1->0)

call BitDly ; задержка

clr SCLPin ; сброс SCL

call BitDly ; завершение старт процедуры

mov A,SlvAdr ; получим адрес ведомого и

call SendByte ; пошлем его в шину

ret

Fault:

setb BusFault ; если ошибка, то установить флаг

ret ; и выйти

;/////////////////////////////////////////

SendData: ; процедура посылки данных (мах 8 байт)в I2C устройство

; в переменной ByteCnt сколько байт послать

; в переменной SlvAdr адрес ведомого

; в регистре R0 адрес буфера с данными

call GoMaster ; занимаем шину и посылаем адрес

jb NoAck,SDEX ; если ведомый не отвечает, то ошибка

SDLoop:

mov A,@R0 ; получим очередной байт из буфера

call SendByte ; пошлем его в шину

inc R0 ; перейдем к следующему байту

jb NoAck,SDEX ; если была ошибка, выходим

djnz ByteCnt,SDLoop ; повторить до конца буфера

SDEX:

call SendStop ; передача закончена, посылка стоп-условия и освобождение шины

ret

;//////////////////////////////////

RcvByte: ; прием байта от I2C устройства

; в Асс принятый байт

mov BitCnt,#8 ; счетчик бит

RBLoop:

call SCLHigh ; прочитаем очередной бит

call BitDly

mov C,SDAPin ; перепишем в С

rlc A ; перепишем бит в А

clr SCLPin ; очистим SCL

call BitDly

djnz BitCnt,RBLoop ; повторим для 8 бит

push Acc ; сохраним Асс

mov A,ByteCnt ;

cjne A,#1,RBAck ; проверим, последний байт или нет

setb SDAPin ; на последний байт подтверждение не выдаем

sjmp RBAClk ; и переходим сразу к выдаче SCL

RBAck:

clr SDAPin ; выдаем подтверждение на непоследний байт

RBAClk:

call SCLHigh ; CLK для подтверждения

pop Acc ; восстановим А

call BitDly ; задержка

clr SCLPin

setb SDAPin ; очистим SDA

call BitDly

ret

;////////////////////////////////////////////

RcvData: ; процедура приема байтов (мах 8) от ведомого I2C устройства

; в переменной ByteCnt сколько байт принять

; в переменной SlvAdr адрес ведомого

; в регистре R0 адрес буфера для данных

inc SlvAdr ; формирование адреса ведомого с запросом на чтение

call GoMaster ; посылка адреса

jb NoAck,RDEX ; проверка, ответил ли ведомый

RDLoop:

call RcvByte ; принимаем байт

mov @R0,A ; сохраняем его

inc R0 ; переходим к следующему адресу буфера

djnz ByteCnt,RDLoop ; повторим для всех байт

RDEX:

call SendStop ; послать стоп-условие и освободить шину

ret

;////////////////////////////////////////////

end.