- •Содержание
- •Введение
- •1. Разработка аппаратных средств
- •1.1. Разработка структурной схемы
- •1.2. Разработка карты распределения адресного пространства мпс
- •1.3 Разработка микропроцессорного модуля
- •1.5 Разработка модуля энергонезависимого озу
- •1.6 Разработка модуля ввода аналоговых величин
- •1.7 Разработка модуля вывода управляющих сигналов
- •1.8 Разработка модуля клавиатуры.
- •1.9 Разработка модуля индикации и аварийной сигнализации
- •2. Расчет электрического сопряжения
- •2.1 Расчет сопряжения по цепям данных
- •3. Расчет аппаратных затрат
- •4. Расчет потребляемой мощности
- •5. Выбор фильтров питания
- •6. Построение временной диаграммы работы мпс
- •7. Разработка програмного обеспечения
- •Заключение
- •Приложение б. Спецификация используемых элементов
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.