Всем привет! Начну со слов благодарности: круто когда есть подобные сайты где всё разжёвано и можно с включением мозгов использовать под свои нужды!
Я взял код из статьи шлюза и встроил его в свой проект.
что есть: attiny2313, pcf8583. напряжение питания 3.3В. Кварц на тиньку 8МГц.
что я сделал(заранее извиняюсь за длинные листинги), привожу те куски кода что не работает, ибо остальное работает:
взял процедурки "как есть"
Код: Выделить всё
; i2c линии
.equ I2C_P = PortB
.equ I2C_D = DdrB
.equ I2C_N = PinB
.equ Clock = 7 ; PortB7/PinB7/DdrB7 - clock SCL
.equ Data = 5 ; PortB5/PinB5/DdrB5 - data SDA
;****************************
.def w = r26 ; это будет наш аккумулятор
.def Bit_counter = r27 ; счётчик бит
.def I2C_flags = r28 ; флаги I2C
;-- флаг 0 - ack, при сброшенном флаге - посылаем ack
;-- флаг 1 - rcv, поднятый флаг - признак ожидания второго байта от компа
;-- (если флаг поднят - значит комп передаёт шлюзу
;-- двухбайтное сообщение и мы ждём второй байт)
.def BTS = r29 ; байт для передачи
.def RDB = r30 ; принятый байт
;****************************
;конфигуригуем выводы IIC шины.
CBI I2C_D, Clock
CBI I2C_D, Data
CBI I2C_P, Clock
CBI I2C_P, Data
;конфигуригуем выводы IIC шины.
;=============================================================================
;--- Процедуры I2C ---------------------------------------
;-- сигнал ack - инвертированный, т.е. если он -----------
;-- ноль - есть ack, если 1 - нет ack --------------------
Clock_null: ; установка нуля на линии Clock
sbi I2C_D,Clock ; переключаем ногу на выход
ret ; (ноль в защёлку мы записали ещё при старте)
Clock_one: ; установка единицы на линии Clock
cbi I2C_D,Clock ; переключаем ногу в Z-состояние
ret
Data_null: ; установка нуля на линии Data
sbi I2C_D,Data ; переключаем ногу на выход
ret ; (ноль в защёлку мы записали ещё при старте)
Data_one: ; установка единицы на линии Data
cbi I2C_D,Data ; переключаем ногу в Z-состояние
ret
;--- start ----------
Start_uslovie: ; формирование старт-условия
rcall Clock_one
rcall Pause_tbuf ; "свободная шина" (4,7 мкс)
rcall Data_null
rcall Pause_thdsta ; "фиксация старт-условия" (4 мкс)
rcall Clock_null
ret
;--- stop -----------
Stop_uslovie: ; формирование стоп-условия
rcall Data_null
rcall Clock_one
wait_clock_p:
sbis I2C_N,Clock ; проверяем шину Clock
rjmp wait_clock_p ; ждём, пока отпустится шина Clock
rcall Pause_tsusto ; "готовность стоп-условия" (4 мкс)
rcall Data_one
ret
;--- transmit -------
Send_Byte:
cbr I2C_flags,0b00000001 ; сбрасываем флаг подтверждения
ldi Bit_counter,8 ; устанавливаем счётчик бит
next_bit_s:
sbrc BTS,7
rcall Data_one ; если передаваемый бит = 1
sbrs BTS,7
rcall Data_null ; если передаваемый бит = 0
rcall Pause_tsudat ; "готовность данных" (250 нс)
rcall Clock_one
wait_clock_s1:
sbis I2C_N,Clock
rjmp wait_clock_s1
rcall Pause_thigh ; длительность полупериода считывания (4 мкс)
rcall Clock_null
lsl BTS ; сдвиг влево
dec Bit_counter ; уменьшаем счётчик
brne next_bit_s ; если счётчик не равен нулю - шлём ещё
rcall Data_one ; если всё - отпускаем линию Data
rcall Pause_tlow ; длительность полупериода установки (4 мкс)
rcall Clock_one
wait_clock_s2:
sbis I2C_N,Clock ; проверяем - отпустилась ли линия Clock
rjmp wait_clock_s2
sbic I2C_N,Data ; проверяем "ack"
sbr I2C_flags,0b00000001 ; если нет - поднимаем флаг
rcall Pause_thigh ; длительность полупериода считывания (4 мкс)
rcall Clock_null ; снова занимаем шину
ret
;--- recieve --------
Recieve_Byte:
clr RDB ; очищаем приёмник
ldi Bit_counter,8 ; устанавливаем счётчик
next_bit_r:
lsl RDB ; сдвигаем влево приёмный регистр
rcall Data_one ; отпускаем линию Data
rcall Pause_tlow ; длительность полупериода установки (4 мкс)
rcall Clock_one ; отпускаем clock
wait_clock_r1:
sbis I2C_N,Clock ; ждём когда отпустится clock
rjmp wait_clock_r1
sbic I2C_N, Data ; если Data=1 - пишем в младший бит приёмника 1,
sbr RDB,0b00000001 ; если нулю - пропускаем эту команду
rcall Pause_thigh ; длительность полупериода считывания (4 мкс)
rcall Clock_null ; роняем clock
dec Bit_counter ; уменьшаем счётчик
brne next_bit_r ; если результат не равен нулю - читаем дальше
sbrs I2C_flags,0
rcall Data_null ; если надо посылать ack - роняем Data
sbrc I2C_flags,0
rcall Data_one ; если не надо посылать ack - отпускаем Data
rcall Pause_tlow ; длительность полупериода установки (4 мкс)
rcall Clock_one ; отпускаем Clock
wait_clock_r2:
sbis I2C_N,Clock ; ждём, пока установится Clock
rjmp wait_clock_r2
rcall Pause_thigh ; даём время slav-у увидеть наш ack
; (или его отсутствие)
rcall Clock_null ; роняем Clock
ret
;--- Конец процедур I2C -------------------------------
;--- Задержки для частоты шины 100 кГц ------
;-- свободная шина (4,7 мкс) --
Pause_tbuf:
ldi w,27
wait_tbuf:
dec w
brne wait_tbuf
ret
;-- фиксация старт-условия (4 мкс) --
Pause_thdsta:
ldi w,23
wait_thdsta:
dec w
brne wait_thdsta
ret
;-- готовность стоп-условия (4 мкс) --
Pause_tsusto:
ldi w,23
wait_tsusto:
dec w
brne wait_tsusto
ret
;-- готовность данных (250 нс) --
Pause_tsudat:
nop
ret
;-- длительность полупериода считывания (4 мкс) --
Pause_thigh:
ldi w,23
wait_thigh:
dec w
brne wait_thigh
ret
;-- длительность полупериода установки (4 мкс) --
Pause_tlow:
ldi w,23
wait_tlow:
dec w
brne wait_tlow
ret
;---------------------------------------------------------
;=============================================================================
как я это использую у себя в проекте:
Код: Выделить всё
; подпрограма считывания времени из pcf8583 НАЧАЛО
GetTimeI2C:
rcall Start_uslovie ; старт шины
ldi BTS, 0xA0 ; выдали адрес часов на запись
rcall Send_Byte
ldi BTS, 0x02 ; выдали адрес ячейки памяти байт
rcall Send_Byte
rcall Start_uslovie ; повторный старт
ldi BTS, 0xA1 ; выдали адрес часов на чтение
rcall Recieve_Byte ; забрали байт секунд
mov tmp2,RDB ; сохранили байт в буфере
rcall Load_Buff_TX
rcall Recieve_Byte ; забрали байт минут
mov tmp2,RDB ; сохранили байт в буфере
rcall Load_Buff_TX
sbr I2C_flags,0b00000001 ; ack - НЕ нужен. ПОСЛЕДНИЙ байт
rcall Recieve_Byte ; забрали байт часов
mov tmp2,RDB ; сохранили байт в буфере
rcall Load_Buff_TX
rcall Stop_uslovie ; Стоп шины
TX_RUN ; отправили результат работы
при запуске кода он выдаёт мне в терминал FF FF FF, то есть считывает единицы с линии и всё. два дня уже мозги морщю, понять не могу. сама микруха pcf8583 рабочаяя - считывал с неё байты через мегу 32 (у неё аппаратный и2ц) - байты показываются корректно.