Страница 1 из 2
Работа TWI по двум датчикам LM75
Добавлено: Вс янв 18, 2026 18:32:22
Satyr7
Здравствуйте! В программировании ботаник, пробую поизучать работу шины I2C. Прописал на ассемблере работу автомата по прерываниям для atmega16 и датчика lm75ad. Всё скомпилировалось и работает в протеусе. И всё бы ничего, но добавил второй lm75 и упëрся как баран. Не пойму как их опросить обоих. Шпаргалки в даташите для опроса одного. Можно пожалуйста попросить пример опроса двух слейвов, хотябы понять как это делается. В обработчике после считывания первого делать рестарт по второму, или выходить из обработчика и инициировать работу автомата по второму? Вообще не понимаю ни первого ни второго. Все попытки ничего не дают. Спасибо если кто-то подскажет.
Re: Работа TWI по двум датчикам LM75
Добавлено: Вс янв 18, 2026 21:35:24
metan
Все устройства на шине и2ц должны иметь уникальный адрес (надеюсь, это обеспечено). Работа программы с одним устройством в принципе не должна отличаться от работы с другим устройством ничем, кроме выбора адреса устройства. Иными словами, можно просто вызывать одну и ту же функцию опроса, передавая ей разные адреса слейвов.
Re: Работа TWI по двум датчикам LM75
Добавлено: Пн янв 19, 2026 07:26:33
Satyr7
Именно это и не понимаю как выполнить. Пытался перед стопом в обработчике сделать рестарт с другим адресом слейва , и пробовал вообще выходить из прерывания и делать по счëтчику входов некое подобие мультиплексора. Ни то ни другое не выходит. Понимаю что делаю что-то неправильно. Шпаргалки нигде не нахожу на ассемблере, хотя вопрос как бы действительно не сложный.
Re: Работа TWI по двум датчикам LM75
Добавлено: Пн янв 19, 2026 07:44:30
Starichok51
Satyr7, как у тебя в программе записаны адреса датчиков?
адрес должен выглядеть так: 1001-А2-А1-А0-Х
Х - это бит для обозначения записи (0) или чтения (1).
если ты точно задал датчикам разные адреса, то работать должно без проблем с каждым адресом.
Re: Работа TWI по двум датчикам LM75
Добавлено: Пн янв 19, 2026 08:29:03
Satyr7
Вот код опроса единичного датчика. Адрес в SLAR именно так и прописывается. Я упёрся на этапе инициализации второго датчика. Где и как это сделать, все мои выверты ни к чему не приводят. Через рестарт в обработчике - нет. Через старт и адресацию из основного цикла - тоже. Как же это сделать правильно?
.include "m16def.inc"
.def temp = r16
.def razr1 = r17
.def razr2 = r18
.def razr3 = r19
.equ FREQ = 8000000
.equ FreqSCL = 400000
.equ FreqTWBR = ((FREQ/FreqSCL)-16)/2
.dseg
Term:
.byte 5
.cseg
.org 0
jmp Reset
.org $022
jmp TWSI
Reset:
ldi temp, high(RAMEND)
out sph, temp
ldi temp, low(RAMEND)
out spl, temp
ldi temp,FreqTWBR
out TWBR,temp
Prog:
sei
rcall Start
rcall Delay
rjmp Prog
TWSI:
cli
rcall Prov_twsr
cpi temp,0x08
breq SLAW_Adr
cpi temp,0x18
breq Pointer
cpi temp,0x28
breq Start
cpi temp,0x10
breq SLAR_Adr
cpi temp,0x40
breq Read_byte1
cpi temp,0x50
breq Read_byte2
cpi temp,0x58
breq TWI_Stop
Vix:
sei
reti
Prov_twsr:
in temp,TWSR
andi temp,0xF8
ret
Start:
ldi temp,0b10100101
out TWCR,temp
ret
TWI_Stop:
ldi r16, 0b00010100
out TWCR, temp
ret
SLAW_Adr:
ldi temp,0b10010000
out TWDR,temp
ldi temp,0b10000101
out TWCR,temp
rjmp Vix
SLAR_Adr:
ldi temp,0b10010001
out TWDR,temp
ldi temp,0b10000101
out TWCR,temp
rjmp Vix
Pointer:
ldi temp,0b00000000
out TWDR,temp
ldi temp,0b10000101
out TWCR,temp
rjmp Vix
Read_byte1:
ldi zh,high(term)
ldi zl,low(term)
in temp,TWDR
st z,temp
rcall TWI_ReciveAck
rjmp Vix
Read_byte2:
ldi zh,high(term+2)
ldi zl,low(term+2)
in temp,TWDR
st z,temp
rcall TWI_ReciveNack
rjmp Vix
TWI_ReciveAck:
ldi r16, 0b11000101
out TWCR, r16
ret
TWI_ReciveNack:
ldi r16, 0b10000101
out TWCR, r16
ret
Error:
ldi zh,high(term+5)
ldi zl,low(term+5)
ldi temp,0xff
st z,temp
rjmp Vix
Delay:
ldi razr1, 255
ldi razr2, 255
ldi razr3, 20
PDelay:
dec razr1
brne PDelay
dec razr2
brne PDelay
dec razr3
brne PDelay
ret
Re: Работа TWI по двум датчикам LM75
Добавлено: Пн янв 19, 2026 08:40:49
akl
[uquote="Satyr7",url="/forum/viewtopic.php?p=4781136#p4781136"]... Пытался перед стопом в обработчике сделать рестарт с другим адресом слейва , и пробовал вообще выходить из прерывания и делать по счëтчику входов некое подобие мультиплексора. Ни то ни другое не выходит. Понимаю что делаю что-то неправильно...[/uquote] Может приведете код инициализации, если не секрет. Чтобы увидеть уставку частоты SCL, например.
Re: Работа TWI по двум датчикам LM75
Добавлено: Пн янв 19, 2026 09:42:02
metan
akl писал(а):приведете код инициализации
да уж и схему бы заодно, а то кофейная гуща почти закончилась

Re: Работа TWI по двум датчикам LM75
Добавлено: Пн янв 19, 2026 15:57:40
Satyr7
Схема в протеус - контроллер и датчик, и подтяжка типовая. Код выше добавил. Изначально сделал библиотеку для дисплея 44760 на I2C и датчика и понял что поженить эти две библиотеки не могу. Стал пробовать на двух датчиках без дисплея. Подскажите пожалуйста хотябы принцип. Если правильно понял - TWI умеет делать опрос нескольких устройств, но мне непонятен способ обращения к нескольким слейвам.
Re: Работа TWI по двум датчикам LM75
Добавлено: Пн янв 19, 2026 16:16:50
Starichok51
Satyr7 писал(а):но мне непонятен способ обращения к нескольким слейвам.
что тут не понятно?
обращаешься к каждому устройству по его адресу.
ты в своем коде показал один адрес датчика (0b10010000).
а какой адрес ты установил у второго датчика?
а может, ты и у первого датчика адресные входы никуда не подключал?
Re: Работа TWI по двум датчикам LM75
Добавлено: Пн янв 19, 2026 16:31:12
Satyr7
Вопрос не в адресе, он задаëтся любым. Мне непонятно как после опроса первого датчика сделать опрос второго. Например: Опрос первого - старт в основном цикле, далее в обработчике прерываний slaw, данные, рестарт, slar, запись температуры, стоп. А что дальше? Как со вторым? Или не делать стоп и в обработчике снова сделать рестарт и slaw второго? Или вообще по-другому? Например делать в основном цикле старт и там же slaw первого? Мне здесь всё непонятно.
Re: Работа TWI по двум датчикам LM75
Добавлено: Пн янв 19, 2026 16:39:59
veso74
Slave устройства I2C отвечают, когда их выбирают по адресу (и не отвечают на запросы по другим адресам). I2C - по двум проводам напр. 128 устройств (с исключениями). Вызываете первый датчик по его адресу, считываете температуру, вызываете второй датчик по адресу (другому), считываете температуру... С помощью выводов программного адреса количество датчиков может достигать 8.
Re: Работа TWI по двум датчикам LM75
Добавлено: Пн янв 19, 2026 16:45:04
Satyr7
Я это понимаю, не понимаю какова процедура на практике. Инициация TWI производится стартом, далее в обработчике производится адресация - это я так сделал, но понимаю, что сделал неправильно, хотя код и работает по одному датчику.
Re: Работа TWI по двум датчикам LM75
Добавлено: Пн янв 19, 2026 16:54:55
Starichok51
вообще не нужно создавать прерывание по TWI - всё прекрасно делается в основном цикле.
сначала делаешь все процедуры по первому датчику, потом - по второму.
я не знаю, какую запись можно или нужно делать в эти датчики.
а чтение делается так:
1. старт.
2. адрес с битом чтения.
3. чтение байтов температуры.
4. стоп.
делаешь эти 4 пункта для первого датчика, потом делаешь эти 4 пункта для второго датчика.
Re: Работа TWI по двум датчикам LM75
Добавлено: Пн янв 19, 2026 17:29:49
Satyr7
Спасибо большое. Понял. Т. е. - делается всё не на прерываниях по кодам статусного регистра, а упрощëнно без проверок. И просто в основном цикле: старт адресация первого... стоп. Далее старт, адресация второго... стоп. Если правильно понял - в обработчике TWSI, как прописано выше в коде, вообще невозможно адресовать больше одного устройства. Просто я предполагал, что можно как-то задать выбор адресов. К примеру: счëтчик 0 - slaw первый, счётчик 1 - slaw второй, ит. д. Но лично у меня этого не получилось.
Re: Работа TWI по двум датчикам LM75
Добавлено: Пн янв 19, 2026 19:02:11
Starichok51
Satyr7 писал(а):сли правильно понял - в обработчике TWSI, как прописано выше в коде, вообще невозможно адресовать больше одного устройства. Просто я предполагал, что можно как-то задать выбор адресов. К примеру: счётчик 0 - slaw первый, счётчик 1 - slaw второй, ит. д.
почему же невозможно в обработчике? по счетчику можно и в обработчике.
но как я уже сказал, обработчик на фиг не нужен.
Satyr7 писал(а):И просто в основном цикле: старт адресация первого... стоп. Далее старт, адресация второго... стоп.
вот именно! без всякого обработчика по очереди всё прекрасно делается в основном цикле.
можно и в обработчике по счетчику, но с обработчиком - бессмысленное усложнение программы.
Re: Работа TWI по двум датчикам LM75
Добавлено: Пн янв 19, 2026 20:40:46
Satyr7
Попробовал по счётчику, только напрасно вспотел, вероятно нужно хорошо понимать все тайминги. Прописал процедуру опроса как вы сказали, нормально скомпилировалось, но пока значения температуры не возвращается, читается только 1-й байт. Всё равно где-то накосячил.
.include "m16def.inc"
.list
.def temp = r16
.def razr1 = r17
.def razr2 = r18
.def razr3 = r19
.equ FREQ = 8000000 // Частота работы чипа 8 Мгц
.equ FreqSCL = 100000 // Максимальная частота работы I2C 400 КГц
.equ FreqTWBR = ((FREQ/FreqSCL)-16)/2 // В формуле учитывается Регистр TWPS == 0
.dseg
Term:
.byte 5
.cseg
.org 0x00
jmp inicio ; PC = 0x0000 RESET
inicio:
LDI R21, HIGH(RAMEND) ;Стек
OUT SPH, R21
LDI R21, LOW(RAMEND)
OUT SPL, R21
HERE:
rcall delay
CALL I2C_INIT ;Включение TWI
CALL I2C_START ;Отправка Старт
LDI R27, 0b10010000 ;SLA(0b1001000) + W(0)
CALL I2C_WRITE ;Отправка SLAW
LDI R27, 0b00000000 ;Задание значения Pointer
CALL I2C_WRITE ;Отправка Pointer
CALL I2C_START ;Рестарт
LDI R27, 0b10010001 ;SLA(0b1001000) + R(0)
CALL I2C_WRITE ;Отправка SLAR
CALL Read_byte1 ;Запись первого байта
nop
nop
CALL Read_byte2 ;Запись второго байта (температуры)
CALL I2C_STOP ;Стоп
RJMP HERE
;----------------------------I2C_INIT-----------------------------
I2C_INIT:
LDI R21, 0
OUT TWSR, R21
LDI R21, (1<<TWEN)
OUT TWCR, R21
RET
;----------------------------I2C_START-----------------------------
I2C_START:
LDI R21, (1<<TWINT)|1<<(TWSTA)|(1<<TWEN)
OUT TWCR, R21
WAIT1:
IN R21, TWCR
SBRS R21, TWINT
RJMP WAIT1
RET
;----------------------------I2C_WRITE -----------------------------
I2C_WRITE:
OUT TWDR, R27
LDI R21, (1<<TWINT)|(1<<TWEN)
OUT TWCR, R21
WAIT3:
IN R21, TWCR
SBRS R21, TWINT
RJMP WAIT3
RET
;----------------------------I2C_STOP------------------------------
I2C_STOP:
LDI R21, (1<<TWINT)|1<<(TWSTO)|(1<<TWEN)
OUT TWCR, R21
RET
Read_byte1:
ldi zh,high(term)
ldi zl,low(term)
in temp,TWDR
st z,temp
rcall TWI_ReciveAck
ret
TWI_ReciveAck:
ldi r16, 0b11000100
out TWCR, r16
ret
Read_byte2:
ldi zh,high(term+2)
ldi zl,low(term+2)
in temp,TWDR
st z,temp
rcall TWI_ReciveNack
ret
TWI_ReciveNack:
ldi r16, 0b10000100
out TWCR, r16
ret
Delay: //
ldi razr1, 255
ldi razr2, 255
ldi razr3, 20
PDelay:
dec razr1
brne PDelay
dec razr2
brne PDelay
dec razr3
brne PDelay
ret
Добавлено after 43 minutes 3 seconds:
Большое спасибо за урок, сделал больше задержку между Read_byte1 и Read_byte2 и нормализовалось, возвращаются оба значения.
Re: Работа TWI по двум датчикам LM75
Добавлено: Вт янв 20, 2026 14:05:35
Starichok51
CALL Read_byte1 ;Запись первого байта
ты делаешь чтение, а в комментарии запись.
вообще не нужна отдельная подпрограмма I2C_INIT. бит TWEN записывается при каждом обращении.
не нужно делать отдельную задержку между чтениями, нужно делать также ожидание окончания операции.
и ожидание окончания лучше сделать подпрограммой, чтобы не повторять "тело" ожидания.
WAIT:
IN R21, TWCR
SBRS R21, TWINT
RJMP WAIT
RET
и будет просто CALL WAIT.
и кстати, в короткой программе следует применять команду относительного вызова RCALL.
Добавлено after 7 hours 6 minutes 51 second:
чтение байтов температуры у тебя сделано не правильно.
нужно сначала запросить передачу байта
rcall TWI_ReciveAck
а уж потом прочитать байт из регистра данных TWDR.
вот мои подпрограммы из моих проектов:
;--- отправка старта по I2C ---
set_start_I2C:
ldi R26, (1<<TWINT)|(1<<TWSTA)|(1<<TWEN)
out TWCR, R26
rcall wait_int_I2C
ret
;--- отправка данных по I2C ---
set_data_I2C:
out TWDR, R27
ldi R26, (1<<TWINT)|(1<<TWEN)
out TWCR, R26
rcall wait_int_I2C
ret
;--- прием данных по I2C ---
in_data_I2C:
ldi R26, (1<<TWINT)|(1<<TWEA)|(1<<TWEN)
out TWCR, R26
rcall wait_int_I2C
in R27, TWDR
ret
;--- ожидание окончания операции по I2C ---
wait_int_I2C:
in R26, TWCR
sbrs R26, TWINT
rjmp wait_int_I2C
in R26, TWSR
ret
я не заморачиваюсь для последнего принятого байта не передавать ответ (Nack). я делаю все чтения всегда с ответом.
и я не передаю стоп. просто последующие старты будут повторными. но ты можешь работать со стопом - на твоё усмотрение.
в подпрограмме ожидания я читаю статус
in R26, TWSR
чтобы проверить успешность операции.
если всегда чтение делать с ответом, то тогда у тебя должно получиться так:
:чтение двух байтов температуры
ldi zh,high(term)
ldi zl,low(term)
CALL Read_byte ; прочитали первый байт
st z+,temp ; сохранили первый байт
CALL Read_byte ; прочитали второй байт
st z+,temp ; сохранили второй байт
Read_byte:
ldi R16, (1<<TWINT)|(1<<TWEA)|(1<<TWEN)
out TWCR, R16
rcall wait
in temp, TWDR
ret
wait:
in R26, TWCR
sbrs R26, TWINT
rjmp wait
ret
как видишь, выглядит намного компактнее, чем твой избыточный код.
но если очень тебе хочется, можешь также две подпрограммы чтения сделать с передачей ответа (Ack) и без передачи ответа, как у тебя сейчас сделано.
и твоей подпрограммы большой задержки не нужно вообще.
Re: Работа TWI по двум датчикам LM75
Добавлено: Вт янв 20, 2026 18:07:19
Satyr7
Спасибо большое. Я изначально всë сделал культурно, просто пока пыхтел с прерываниями снова понаделал всякой мешанины, предполагая, что если часть кода сделать в общей куче, то это должно как-то положительно отразиться. Все замечания исправлю. Способ выбора адресации слейвов в TWI пока отложил, т. к. моих познаний пока не хватает. Обрадовался, что получилось всё в цикле. Справлюсь с выводом на дисплей и вернусь к вопросу. Если я вам ещё не надоел, позже выложу свою стряпню. Спасибо.
Re: Работа TWI по двум датчикам LM75
Добавлено: Вт янв 20, 2026 18:46:36
Starichok51
Satyr7 писал(а):Способ выбора адресации слейвов в TWI пока отложил, т. к. моих познаний пока не хватает.
тебе уже насколько раз сказали, что с адресацией проблем нет.
ты первому датчику задал "нулевой" адрес (000). второму датчику адресные входы подключи, например, 001. и обращайся по адресу 0b1001001 + бит записи или чтения.
Satyr7 писал(а):Если я вам ещё не надоел
не надоел.
вменяемым людям помогать даже приятно.
но, к сожалению, попадаются невменяемые...
Re: Работа TWI по двум датчикам LM75
Добавлено: Вт янв 20, 2026 19:06:27
Satyr7
Невменяемые это такие бивни как я, потому-что именно так всё и делал. Я прекрасно знаю как притяжками задавать физический адрес. Здесь просто смешались понятия, задания адреса на ногах, и адресации слейва в обработчике. Сидит, например, какой-нибудь придурковатый нуб, читает даташит и чешет тупую репу, и думает что ему делать дальше. Дальше начинает методом насильного впихивания лепить в обработчике всякие рестарты, надеясь что этот TWI каким-то чудом заработает. А в итоге, делать ему остаëтся только одно - идти в ближайшую поликлинику и просить таблетку от критинизма.