Распространяемые в Internet библиотеки зачастую также имеют подробные комментарии и файлы описаний,
ЛИСТИНГ ПРОГРАММЫ ДРАЙВЕРА ЧАСОВ
Программа управления часами-термометром с
жидкокристаллическим индикатором
Использованные компоненты схемы:
Микроконтроллер - PIC16F84 04I/P
Часы реального времени - DS1307
Термометр - DS1621
Индикатор - ИЖЦ21 -4/7
Регистры индикатора - КР1533ИР24 (4шт)
Используемые выводы микроконтроллера:
АО (17) - строб записи в регистры ,
А1 (18) - данные для индикации
A2(1) -SCL
A3 (2) - SDA
А4 (3) - вход 4кГц для таймера
B1 (7) - вход кнопки "+минута"
B2 (8) - вход кнопки "+час"
B3 (9) - подложка для LCD индикатора
list p=16F84
#include <pl 6F84.inc>
_CONFIG _CP_OFF&_ WDT_OFF & _ PWRTE_ON &_XT_OSC
w_temp EQU 0x0C ; переменная для временного хранения
status_temp EQU 0x0D ; переменная для временного хранения
count 1 EQU ОхОЕ ; рабочий счетчик
count2 EQU OxOF ; рабочий счетчик
count3 EQU 0x10 ; рабочий счетчик
count4 EQU Ox 11 ; рабочий счетчик
flags EQU Ox 12 ; переменная для хранения флаг-битов
work data EQU Ox 13 ; рабочая переменная
digit 1 EQU 0x14 ; значение для первого знакоместа
digit2 EQU 0x15 ; значение для второго знакоместа
digit3 EQU Ox 16 ; значение для третьего знакоместа
digit4 EQU Ox 17 ; значение для четвертого знакоместа
digitemp EQU 0x18 ; промежуточное значение знакоместа
disp EQU Ox 19 ; счетчик времени отображения
bin EQU 0x1 А ; рабочая переменная
tens_and_ones EQU Ox IB ; рабочая переменная для перекодировки
hundreds EQU Ox 1С ; рабочая переменная для перекодировки
timelenght EQU 0x06 ; длительность индикации времени, сек
templenght EQU 0x06 ; длительность индикации температуры, сек Импортированные переменные для подпрограмм работы с шиной I2C
STATU EQU 20 ; Переменная состояния
FLAG EQU 21 ; Переменная флагов общего назначения
I2CDEV EQU 22 ; Битовый буфер
ERCODE EQU 23 ; Код ошибки (для индикации занятости линии)
ADDR EQU 24 ; Переменная адреса
DATAI EQU 25 ; Переменная для хранения входных данных
DATAO EQU 26 ; Переменная для хранения выходных данных
DATAI_1 EQU 27 ; Переменная для хранения входных данных
DATAO 1 EQU 28 ; Переменная для хранения выходных данных
SLAVE EQU 29 ; Адрес устройства (YYYYxxx0)
TXBUF EQU 2А ; Буфер передачи
RXBUF EQU 2В ; Буфер приема
COUNT EQU 2С ; Счетчик битов
Битовые переменные (флаги) подпрограмм работы с шиной I2C
ERR1 EQU 0 ; Флаг-бит ошибки (здесь не используется)
SDA EQU 3 ; RA3, вход/выход данных (SDA)
SLC EQU 2 ; RA2. тактовая частота (SCL)
DI EQU 7 ; Входной бит подпрограммы I2C
DO EQU 6 ; Выходной бит подпрограммы I2C
ORG 0x000
goto main
ORG 0x000 ; вектор прерывания
movwf w. temp ; сохранение текущего значения W
movf STATUS.w ; перенос содержимого STATUS в W
movwf statusjemp ; сохранение содержимого регистра STATUS
clfr TMR0 ; очистка таймера
bcf INTCON,T0IF ; сброс флага прерывания
btfsc flags, 1 ; если flags<1>=0 отображаем время
goto tempread ; если flags< 1 >= 1 отображаем температуру
timeread callclock ; чтение текущего значения времени
btfss flags, 0 ; разделитель включен?
goto d_point ; если нет,
bsf digit2, 7 ; то включаем разделичелъ
bcf flags, 0 ; сбрасываем флаг разделителя
goto gohome ; и выходим из подпрограммы
d_point bcf digit2, 7 ; иначе выключаем разделитель
bsf lags, 0 ; устанавливаем флаг разделителя
decfsz disp, f ; уменьшаем на 1 время индикации. Время истекло?
goto gohome ; нет, продолжаем отображать часы
bsf flags, 1 ; иначе устанавливаем флаг индикации температуры
movlw templenght ; и загружаем в disp
movwf disp ; длительность ее отображения
goto gohome
tempread call celsio; чтение текущего значения температуры
btfss flags, О
goto zerot
bcf flags, 0
goto gohome
zerot bsf flags, 0
decfsz disp, f ;уменьшаем на 1 время индикации. Время истекло?
goto gohom ; нет, продолжаем отображать термометр
bcf flags, 1 ; если да, сбрасываем флаг индикации температуры
movlw timelenght ; и устанавливаем длительность отображения времени
movwf disp
movlw 0x9E ; обращаемся к термометру
movwf SLAVE
movlw 0x9E ; с командой начать новое измерение
movwf ADDR
call WRCOM
gohome movf status_temp,w ; чтение копии регистра STATUS
movwf STATUS ; восстановление значения регистра STATUS swapf w_temp,f
swapf w_temp,w ; восстановление значения аккумулятора W
retfie ; возврат из прерывания
main clrf PORTA
clrf PORTB
clrf flags
movlw timelenght
movwf disp
clrwdt ; очистка WDT и пределителя
bsf STATUS, RPO ; bank 1
movhvb '01110010';
movwf OPTION_REG
movlw b'l 1110000'
movwf PORTA
movlw b’11110111’
movwf PORTB
bcf STATUS, RPO, bank 0
инициализация часов (DS1307) и термометра (DS1621)
movlw 0х9Е ; записываем в SLAVE адрес термометра
movwf SLAVE
movlw 0хАС ; адрес регистра конфигурации термометра
movwf ADDR
movlw 0x0B ; режимы термометра: POL-high, ISHOT-yes
movwf DATAO
call WRBYTE ; подпрограмма записи байта
nop ; защитный интервал
movlw 0x9E ; обращение к термометру
movwf SLAVE
movlw 0xEE ; команда начать измерение температуры
movwf ADDR
call WRCOM ; запись команды в термометр
nop ; защитный интервал
movlw 0xD0 ; проверка пропадания питания
movwf SLAVE ; установили адрес часов
movlw 0x00 ; установили адрес регистра состояния
movwf ADDR
call RDBYTE ; считываем регистр состояния
btfss DATAI,7 ; если питание не пропадало, обходим инициализацию
goto okay ; и начинаем отображать время и температуру
movlw 0xD0 ; иначе - инициализируем часы
movwf SLAVE
clrw
movwf ADDR ; кварцевый генератор включен
movwf DATAO ; счетчик секунд сброшен
call WRBYTE ; запись байта
nop
movlw 0xD0 ; адрес для обращения к часам
movwf SLAVE
movlw 0x01
movwf ADDR
movlw 0x00 ; обнуление счетчика минут
movwf DATAO
call WRBYTE
nopmovlw 0xD0 ; адрес для обращения к часам
movwf SLAVE
movlw 0x02
movwf ADDR
movlw 0x00 ; обнуление счетчика часов
movwf DATAO
call WRBYTE
nop
movlw 0xD0 ; адрес для обращения к часам
movwf SLAVE
movlw 0x07 ; адрес контрольного регистра
movwf ADDR ; устанавливаем режим отображения 24 часа
movlw 0x91 ; и частоту 4кГц на выходе Tout
movwf DATAO
call WRBYTE
nop;
okay clrf TMR0 ; очищаем таймер
movlw b'10100000'
movwf INTCON ; разрешаем прерывание no TMR0
repeat btfss PORTB, 1 ; нажата кнопка "+минута"?
call mninc ; если да, увеличить значение минут
call ind_LCD ; иначе обновить значение на индикаторе
btfss PORTB, 2 ; нажата кнопка "+час"?
call hrinc ; если да, увеличить значение часов
call ind_LCD ; иначе обновить значение на индикаторе
goto repeat
чтение текущего времени из часов
clock movlw 0xD0
movwf SLAVE
movlw 0x01
movwf ADDR
call RDBYTEN ; чтение двух байтов: 01H, 02Н
movf DATAI,W
andlw 0x0F
call convert ; табличная перекодировка
movwf digit4
swapf DATAI,F
movf DATAI,W
andlw 0x07
call convert ; табличная перекодировка
movwf digit3
movf DATAI_1,W
andlw 0x0F
call convert ; табличная перекодировка
movwf digit2
swapf DATAI_1,F
movf DATAI_1,W
andlw 0x03
btfsc STATUS,Z
movlw 0x0A
call convert ; табличная перекодировка
movwf digit 1
return
чтение значения температуры из термометра
celsio movlw
b’00000000’ ; гасим первое знакоместо
movwf digit 1 ;
movlw b'01100011' ; символ "градус"
movwf digit4 ; в четвертое знакоместо
movlw 0х9Е
movwf SLAVE
movlw 0xAA
movwf ADDR
call RDBYTEN ; MSB-LSB
movlw b'01000000' ; символ минус
btfss DATAI.7 ; если бит 7= 1, то температура отрицательная
goto rotate
decf DATAI,f
movwf digit 1 ; записали символ минус в первое знакоместо
movlw 0xFF
xorwf DATAI,F
rotate movf DATAI,W
movwf bin
bcf bin,7
call binary_to_bcd ; подпрограмма конвертации
movf tens_and_ones,W
andlw 0x0F
call convert
movwf digit3
swapf tens_and_ones,F
movf tens_and_ones,W
andlw 0x0F
call convert
movwf digit 2
xorlw 0x3F
btfss STATUS, Z
return ;если в 2-м знакоместе незначащий ноль
movf digit3, w ; то для лучшей читаемости значения
movwf digit2 ; переносим значение из 3-го знакоместа в 2-е
clrf digit4 ; гасим 4-е знакоместо
movlw b'01100011' ;символ "С"
movwf digit3 ; в третье знакоместо
movf digit2, w
xorlw 0x3F
btfss STATUS, Z ; если температура ноль градусов,
return
clrf digit 1 ; то символ "плюс/минус" не отображаем
return
подпрограмма отображения 4 символов на ЖК-индикаторе
indJXDbcfPORTB,3 ; уровень на подложке в 0
movf digit 1, w ; первая цифра в аккумуляторе
movwf digitemp
call loader ; выгрузили биты в индикатор
movf digit2, w ; вторая цифра в аккумуляторе
movwf digitemp
call loader ; выгрузили биты в индикатор
movf digit 3, w ; третья цифра в аккумуляторе
movwf digitemp
call loader ; выгрузили биты в индикатор
movf digit4,w ; четвертая цифра в аккумуляторе
movwf digitemp
call loader ; выгрузили биты в индикатор
call delay ; все данные выгружены, держим …. . . ;данные на индикаторе
bsfPORTB,3 ; уровень на подложке в 1
movf digitl,w ; первая цифра в аккумуляторе
xorlw 0xFF ; инверсия всех битов
movwf digitemp
call loader ; выгрузили биты в индикатор
movf digit2, w ; вторая цифра в аккумуляторе
xorlw 0xFF ; инверсия всех битов
movwf digitemp
call loader ; выгрузили биты в индикатор
movf digit3, w ; третья цифра в аккумуляторе
xorlw 0xFF ; инверсия всех битов
movwf digitemp
call loader ; выгрузили биты в индикатор
movf digit4,w ; четвертая цифра в аккумуляторе
xorlw 0xFF ; инверсия всех битов
movwf digitemp
call loader ; выгрузили биты в индикатор
call delay ; все данные выгружены, держим …. . . ;данные на индикаторе
return
подпрограмма табличной конвертации
принимает и возвращает данные в w
convert addwfPCL, f
retlw b’00111111’
retlw b’00000110’
retlw b’01011011’
retlw b’01001111’
retlw b’01100110’
retlw b’01101101’
retlw b’01111101’
retlw b’00000111’
retlw b’01111111’
retlw b’01101111’
retlw b’00000000’
retlw b’01000000’
retlw b’00111001’
retlw b’01011110’
retlw b’01111001’
подпрограмма выгрузки знакоместа в регистры,
данные в переменной digitemp
loader movlw 0x08
movwf count3
nextbit bcf PORTA, 0 ; строб в 0
btfss digitemp, 7 ; проверяем старший бит
bcf PORTA, 1 ; установили порт А1 в 0, если текущий бит=0
btfsc digitemp, 7
bsf PORTA, 1 ; установили порт А1 в 1, если текущий бит=1
bsf PORTA, 0 ; строб в 1, бит записан в регистр
rlf digitemp, f ; сдвиг данных
decfsz count3, f
goto nextbit
return
подпрограмма обработки кнопки "+час"
hrinc clrf INTCON ; запрещаем все прерывания
bcf flags, 1
movlw timelenght ;переустанавливаем время работы в режиме «часы»
movwf disp
movlw 0xD0 ; читаем текущее время
movwf SLAVE
movlw 0x02
movwf ADDR
call RDBYTE
swapf DATAI, w
andlw0x0F
movwf digitemp ; выделили старший полубайт в digitemp
btfss digitemp, 1 ; если старший разряд не равен 2
goto high 1 ; уходим на другой фрагмент
movf DATAI, w
andlw 0x0F ; выделяем младший полубайт
addlw0x01
movwf w_temp
btfsc w_temp, 2
clrf w_temp ; если младший разряд часов =4 обнуляем его
movf w_temp, f
btfsc STATUS, Z
clrf digitemp ; и обнуляем старший разряд, получили 00 часов
goto sethr
highl movf DATAI, w
andlw 0x0F ;выделяем младший полубайт
addlw0x01
movwf w_temp
sublw 0х0А
btfsc STATUS, Z
clrf w_temp ; если младший разряд часов больше 9 обнуляем
btfsc STATUS, Z
incf digitemp, f ; прибавляем 1 в старший разряд
sethr swapf digitemp, f
movf digitemp, w
iorwf w_temp, f ; соединили старший и младший разряды в w_temp
movlw 0xD0
movwf SLAVE
movlw 0x02
movwf ADDR
movf w_temp, w
movwf DATAO
call WRBYTE ; записали новое значение в часы
call clock ; читаем новое значение времени
bsfdigit2, 7 ; разделитель постоянно включен
movlw 0x10
movwf count4
reindh call ind_LCD ; выполняем задержку в 10h циклов индикации
decfsz count4, f
goto reindh
clrf TMR0 ; очищаем таймер
movlw b’10100000’
movwf INTCON ; разрешаем прерывание по TMR0
return
подпрограмма обработки кнопки "+минута"
mninc clrf INTCON
bcf flags, 1
movlw timelenght ; увеличиваем время работы в режиме "часы"
movwf disp
movlw 0xD0 ; читаем текущее время
movwf SLAVE
movlw 0x01
movwf ADDR
call RDBYTE
swapf DATAI, w
andlw 0x0F
movwf digitemp ; выделили старший полубайт в перем. digitemp
sublw 0x05
btfss STATUS, Z ; если старший разряд не равен 5
goto high4 ; уходим на другой фрагмент
movf DATAI, w
andlw 0x0F ; выделяем младший полубайт
addlw 0x01
movwf w_temp
sublw 0x0A
btfsc STATUS, Z
clrf w_temp ; если младший разряд минут =10 обнуляем его
btfsc STATUS, Z
clrf digitemp ; и обнуляем старший разряд, получили 00 минут
goto setmin
high4 movf DATAI, w
andlw 0x0F ; выделяем младший полубайт
addlw 0x01
movwf w_temp
sublw 0x0A
btfsc STATUS, Z
clrf w_temp ; если младший разряд минут больше 9 обнуляем
btfsc STATUS, Z
incf digitemp, f ; прибавляем 1 в старший разряд
setminswapf digitemp, f
movf digitemp, w
iorwf w_temp, f ; соединили старший и младший разряды в w_temp
movlw 0xD0
movwf SLAVE
movlw 0x01
movwf ADDR
movf w_temp, w
movwf DATAO
call WRBYTE ; записали новое значение в часы
call clock ; читаем новое значение времени
bsfdigit2,7 ; разделитель постоянно включен
movlw 0x10
movwf count4
reindm call ind_LCD
decfsz count4, f
goto reindm
clrf TMRO ; очищаем таймер
movlw b'10100000'
movwf INTCON ; разрешаем прерывание по TMRO
return
подпрограмма задержки
delay movlw 0x10
movwf count 1
loop2 movlw 0xA0
movwf count2
loopl decfsz count2,1
goto loop 1
decfsz count 1,1
goto loop2
return
ИМПОРТИРОВАННЫЕ ПОДПРОГРАММЫ
Запись одного байта данных в устройство I2C
Входные данные: DATAO = байт данных для записи
ADDR - адрес назначения (в устройстве)
SLAVE = адрес устройства в схеме (1010xxx0)
WRBYTE
MOVF SLAVE,W ; Переносим адрес устройства
MOVWF TXBUF ; в буфер передачи
CALL BSTART ; Генерируем бит START
CALL ТХ ; Передаем адрес устройства
MOVF ADDR,W ; Переносим адрес назначения
MOVWF TXBUF ; в буфер передачи
CALL ТХ , ; Передаем адрес назначения
MOVF DATAO,W ; Переносим данные
MOVWF TXBUF ; в буфер передачи
CALL ТХ ; Передаем данные и анализируем подтверждение
CALL BSTOP ; Генерируем бит STOP
RETURN
Запись команды в устройство I2C
Входные данные: ADDR = команда
SLAVE = адрес устройства в схеме (1010xxx0)
WRCOM
MOVF SLAVE.W ; Переносим адрес устройства
MOVWF TXBUF ; в буфер передачи
CALL BSTART ; Генерируем бит START
CALL TX ; Передаем адрес устройства
MOVF ADDR.W ; Переносим слово команды
MOVWF TXBUF ; в буфер
CALL TX ; Передаем команду
CALL BSTOP ; Генерируем бит STOP
RETURN
Запись ДВУХ байтов данных в устройство I2C
Входные данные: DATAO = 1-й байт данных для записи
DATAO_l = 2-й байт данных для записи
ADDR = адрес назначения (в устройстве)
SLAVE = адрес устройства в схеме (1010xxx0)
WRBYTEN
MOVF SLAVE.W ; Переносим адрес устройства
MOVWF TXBUF ; в буфер передачи
CALL BSTART ; Генерируем бит START
CALL TX ; Передаем адрес устройства
MOVF ADDR,W ; Переносим адрес назначения
MOVWF TXBUF ; в буфер передачи
CALL TX ; Передаем адрес назначения
MOVF DATAO,W ; Переносим первый байт данных
MOVWF TXBU ; в буфер передачи
CALL ТХ ; Передаем данные и анализируем подтверждение
MOVF DATAO_l,W ; Переносим второй байт данных MOVWF TXBUF ; в буфер передачи CALL ТХ ; Передаем данные и анализируем подтверждение
CALL BSTOP ; Генерируем бит STOP
RETURN
Чтение байта данных из устройства I2C
Входные данные: ADDR = адрес назначения (в устройстве)
SLAVE = адрес устройства в схеме (1010xxx0)
Выходные данные: DATAI = байт данных
RDBYTE
MOVF SLAVE,W ; Переносим адрес устройства
MOVWF TXBUF ; в буфер передачи (R/W - 0)
CALL BSTART ; Генерируем бит START
CALL ТХ ; Передаем адрес устройства
MOVF ADDR,W ; Переносим адрес назначения
MOVWF TXBUF ; в буфер передачи
CALL TX ; Передаем адрес назначения
CALL BSTART ; Генерируем бит START
MOVF SLAVE,W ; Переносим адрес устройства
MOVWF TXBUF ; в буфер передачи
BSF TXBUF,0 ; Устанавливаем режим READ (R/W=1)
CALL TX ; Передаем адрес устройства
CALL RX ; Читаем байт и подтверждение
CALL BSTOP ; Генерируем бит STOP
MOVF RXBUF,W ; Сохраняем данные
MOVWF DATAI ; в буфере приема DATAI
RETURN
Чтение ДВУХ байтов данных из устройства I2C
Входные данные: ADDR = адрес назначения (в устройстве)
SLAVE = адрес устройства в схеме (1010ххх0)
Выходные данные: DATAI = 1-й байт данных
DATAI _1 = 2-й байт данных
RDBYTEN
MOVF SLAVE,W ; Переносим адрес устройства
MOVWF TXBUF ; в буфер передачи (R/W = 0)
CALL BSTART ; Генерируем бит START
CALL TX ; Передаем адрес устройства
MOVF ADDR,W ; Переносим адрес назначения
MOVWF TXBUF ; в буфер передачи
CALL TX ; Передаем адрес назначения
CALL BSTART ; Генерируем бит START
MOVF SLAVE,W ; Переносим адрес устройства
MOVWF TXBUF ; в буфер передачи
BSF TXBUF,0 ; Устанавливаем режим READ (R/W = 1)
CALL TX ; Передаем адрес устройства
CALL RXO ; Читаем первый байт и подтверждение
MOVF RXBUF,W ; Сохраняем данные
MOVWF DATAI ; в буфере приема DATAI
CALL RX ; Читаем второй байт и подтверждение
MOVF RXBUF,W ; Сохраняем данные
MOVWF DATAI_1 ; в буфере приема DATAI_1
CALL BSTOP ; Генерируем бит STOP
RETURN
Подпрограмма генерации бита START
Генерируется бит START (SCL удерживается в состоянии 1,
пока на SDA происходит переход от высокого уровня к низкому)
затем проверяется состояние линии SCL.
Входных и выходных данных нет.
BSTART
MOVLW B'00000000' ; Настраиваем SCL и SDA на вывод
MOVWF PORTA ; В СООТВЕТСТВИИ СО СХЕМОЙ!!! BSF PORTA,SDA ; надо быть уверенным, что SDA=1
BSF PORTA,SCL ;устанавливаем SCL=1
MOVLW 1 ; предполагаемый код ошибки 1
BTFSS PORTA,SCL ; линия блокирована?
CALL ERR ; если да, обработка кода ошибки
BCF PORTA,SDA ; переводим SDA в 0, пока SCL=1
NOP ; защитный временной интервал
NOP
NOP
BCF PORTA,SCL ; сбрасываем SCL, START выполнен
RETLW 0
Генерация бита STOP
Генерируется бит STOP (состояние SDA переходит из 0 в 1,
пока на SCL удерживается высокий уровень)
Входных и выходных данных нет.
BSTOP
MOVLW В’00000000’ ; Настраиваем SCL и SDA на вывод
MOVWFPORTA ; В СООТВЕТСТВИИ СО СХЕМОЙ!!!
BCF PORTA,SDA ; Устанавливаем SDA=0
BSF PORTA,SCL ; Устанавливаем SCL=0
NOP ; Защитный временной интервал
NOP
NOP
MOVLW 1 ; Предполагаемый код ошибки 1
BTFSS PORTA.SCL ;SCL=1?
CALL ERR ; Нет, SCL удерживается устройством D0
BSF PORTA.SDA ; Переводим SDA из 0 в 1, пока SCL=0
MOVLW 4 ; Предполагаемый код ошибки 4
BTFSS PORTA,SDA ;SDA=1?
CALL ERR ; Нет, SDA не освобождается для STOP
RETLW О
Получение бита данных из устройства I2C в PIC
BITIN MOVLW B'00001000' ; SDA - ввод, SCL - вывод
MOVWF PORTA ; В СООТВЕТСТВИИ CO СХЕМОЙ
BSF PORTA,SDA
BCF I2CDEV.DI ; DI=0
BSF PORTA,SCL ;SCL=1
MOVLW 1 ; Предполагаемый код ошибки
BTFSC PORTA,SCL ; Пропустить, если SCL=0
GOTO BIT1
BTFSS FLAG,ERR 1 ; Первая ли ошибка обнаружена?
MOVWF ERCODE ; Сохранить код ошибки
BSF FLAG,ERR 1 ; Установить флаг ошибки
BIT1 BTFSC PORTA,SDA ; Читать данные с SDA
BSF I2CDEV,DI ; DI=1 (если считана 1)
NOP ; Защитная задержка
NOP
BCF PORTA SCL ; SCL=0
RETLW 0
Передача бита данных из PIC в устройство I2C
BITOUT
MOVLW B'00000000' ; SDA, SCL на вывод
MOVWF PORTA ; В СООТВЕТСТВИИ CO СХЕМОЙ
BTFSS I2CDEV,DO ;DO=0?
GOTO BITO ; если да, перейти на BITO
BSF PORTA,SDA ;SDA=1
MOVLW 2 ; предполагаемый код ошибки 2
BTFSC PORTA,SDA ; проверка на наличие ошибки 2
GOTO CLK1 ; если ошибки нет, уйти на CLK1
BTFSS FLAG JERRI ; первая ли ошибка обнаружена?
MOVWF ERCODE ; сохраняем код ошибки
BSF FLAG,ERR1 ; устанавливаем флаг наличия ошибки
GOTO CLK1
BITO BCF PORTA,SDA ; SDA=0
NOP ; защитная задержка
NOP
NOP
NOP
NOP
CLK1BSF PORTA.SCL ;SCL=1
MOVLW 1 ; предполагаемый код ошибки 1
BTFSC PORTA,SCL ; SCL удерживается в 0?
GOTO ВГТ2 ; если нет, перейти на ВIТ2
BTFSS FLAG,ERR1 ; если да,
MOVWF ERCODE ; сохранить код ошибки
BSF FLAGJERR1 ; установить флаг наличия ошибки
BIT2 NOP ; защитная задержка
NOP
NOP
BCF PORTA,SCL ; возврат SCL в 0
RETLW 0
Получение 8-битных данных из устройства I2C в PIC
Входных данных нет
Выходные данные: принятый байт в переменной RXBUF
RX MOVLW .8 ; количество принимаемых битов
MOVWF COUNT
CLRF RXBUF; очистка буфера приема
RXLP RLF RXBUF, F ; сдвиг данных в буфере из бита переноса
SKPC ; пропустить, если CARRY=1
BCF RXBUF,0 ; очистка нулевого бита RXBUF
SKPNC ; пропустить, если CARRY=0
BSF RXBUF,0 ; установить в 1 нулевой бит RXBUF
CALL BITIN ; прочитать бит из устройства
BTFSC I2CDEV,DI ; если входной бит = 1, установить
BSF RXBUF,0 ; в 1 нулевой бит RXBUF
DECFSZ COUNT, F ; все биты получены?
GOTO RXLP ; нет, продолжить
BSF I2CDEV,DO ; установить бит протокола ASK=1
CALL BITOUT ; для прекращения дальнейшего обмена данными
RETLW 0
Получение 8-битных данных, в случае, если ASK=0
Полученный байт данных помещается в переменную RXBUF
RXO MOVLW .8 ; количество принимаемых битов
MOVWF COUNT
CLRF RXBUF ; очистка буфера приема
RXLP0
RLF RXBUF, F
SKPC
BCF RXBUF.0
SKPNC
BSF RXBUF.0
CALL BITIN
BTFSC I2CDEV.DI
BSF RXBUF,0
DECFSZ COUNT, F
GOTO RXLP0
BCF I2CDEV.DO ; установить бит протокола ASK=0(!!!)
CALL BITOUT ; для прекращения дальнейшего обмена данными
RETLW 0
Побитная передача данных из PIC в устройство I2C
Входные данные: байт в переменной TXBUF
Выходные данные: нет
Данные выводятся побитно через бит переноса CARRY
ТХ MOVLW .8 ; количество передаваемых битов
MOVWF COUNT
TXLP BCF I2CDEV,DO ; фиксируем выходной бит DO=0
BTFSC TXBUF/7 ; если выводимый бит = 0, DO=0
BSF I2CDEV,DO ; иначе DO= 1
CALL BITOUT ; подпрограмма вывода бита
RLF TXBUF, F ; сдвиг TXBUF влево
SKPC ; f(6) --> f(7)
BCF TXBUF,0 ; f(7) —> carry
SKPNC ; carry —> f(0)
BSF TXBUF,0
DECFSZ COUNT, F ; все биты выведены?
GOTO TXLP ; нет, продолжить
CALL BITI ; читаем бит протокола ASK
MOVLW 3 ; предполагаемый код ошибки
BTFSC I2CDEV,DI ; проверяем бит ASK
CALL ERR ; нет подтверждения от устройства
RETLW 0
Подпрограмма обработки кода ошибок шины I2C
Входные данные: регистр W - код ошибки
Выходные данные: переменная ERCODE - код ошибки
FLAG(ERR1)=1
код причина появления ошибки
1 SCL удерживается в 0 (шина постоянно занята)
2 SDA удерживается в 0 (шина постоянно занята)
3 Нет ответа от устройства
4 SDA не освобождается для генерации бита STOP
Подпрограмма идентифицирует состояние линий SCL и SDA в соответствии
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.