Интерфейсная шина IIC (I2C)

Распечатать


Один из моих самых любимых интерфейсов. Разработан в компании Philips и право на его использование стоит денег, но все на это дружно положили и пользуют в свое удовольствие, называя только по другому. В Atmel его зовут TWI, но от этого ничего не меняется :) Обычно при разборе IIC во всех книгах ограничиваются примером с EEPROM на этом и ограничиваются. Да еще юзают софтверный Master. Не дождетесь, у меня будет подробный разбор работы этой шины как в режиме Master так и Slave, да еще на аппаратных блоках с полным выполнением всей структуры конечного автомата протокола. Но об этом после, а сейчас основы.

Физический уровень.
Данные передаются по двум проводам — провод данных и провод тактов. Есть ведущий(master) и ведомый (slave), такты генерирует master, ведомый лишь поддакивает при приеме байта. Всего на одной двупроводной шине может быть до 127 устройств. Схема подключения — монтажное И


Передача/Прием сигналов осуществляется прижиманием линии в 0, в единичку устанавливается сама, за счет подтягивающих резисторов. Их ставить обязательно всегда! Стандарт! Резисторы на 10к оптимальны. Чем больше резистор, тем дольше линия восстанавливается в единицу (идет перезаряд паразитной емкости между проводами) и тем сильней заваливаются фронты импульсов, а значит скорость передачи падает. Именно поэтому у I2C скорость передачи намного ниже чем у SPI. Обычно IIC работает либо на скорости 10кбит/с — в медленном режиме, либо на 100кбит/с в быстром. Но в реальности можно плавно менять скорость вплоть до нуля.
Ни в коем случае нельзя переключать вывод микроконтроллера в OUT и дергать ногу на +5. Можно запросто словить КЗ и пожечь либо контроллер либо какой-нибудь девайс на шине. Мало ли кто там линию придавит.

Вся передача данных состоит из Стартовой посылки, битов и стоповой посылки. Порядок изменения уровня на шинах задает тип посылки.



После старта передача одного бита данных идет по тактовому импульсу. То есть когда линия SCL в нуле master или slave выставляют бит на SDA (прижимают — если 0 или не прижимают — если 1 линию SDA) после чего SCL отпускается и master/slave считывают бит. Таким образом, у нас протокол совершенно не зависит от временных интервалов, только от тактовых битов. Поэтому шину I2C очень легко отлаживать — если что то не так, то достаточно снизить скорость до байта в минуту и спокойно, обычными вольтметрами, смотреть что у нас происходит. Правда это не прокатит с железным I2C, там нет таких низких скоростей. Но что нам мешает затактовать микроконтроллер от ОЧЕНЬ медленного тактового генератора и отладить все по шагам? ;)

Повторим для ясности:

  • Начало передачи определяется Start последовательностью — провал SDA при высоком уровне SCL
  • При передаче информации от Master к Slave, ведущий генерирует такты на SCL и выдает биты на SDA. Которые ведомый считывает когда SCL становится 1.
  • При передачи информации от Slave к Master, ведущий генерирует такты на SCL и смотрит что там ведомый творит с линией SDA — считывает данные. А ведомый, когда SCL уходит в 0, выставляет на SDA бит, который мастер считывает когда поднимет SCL обратно.
  • Заканчивается все STOP последовательностью. Когда при высоком уровне на SCL линия SDA переходит с низкого на высокий уровень.


То есть, изменение на шине данных в момент приема данных может быть только при низком уровне на SCL. Когда SCL вверху то идет чтение. Если же у нас SDA меняется при высоком SCL, то это уже служебные команды START или STOP.

Если Slave торомоз и не успевает (у EEPROM, например, низкая скорость записи), то он может насильно положить линию SCL в землю и не давать ведущему генерировать новые такты. Мастер должен это понять и дать слейву прожевать байт. Так что нельзя тупо генерить такты, при отпускании SCL надо следить за тем, что линия поднялась. Если не поднялась, то надо остановиться и ждать до тех пор, пока Slave ее не отпустит. Потом продолжить с того же места.

Логический уровень
Как передаются отдельные биты понятно, теперь о том что эти биты значат. В отличии от SPI тут умная адресная структура. Данные шлются пакетами, каждый пакет состоит из девяти бит. 8 данных и 1 бит подтверждения/не подтверждения приема.

Первый пакет шлется от ведущего к ведомому это физический адрес устройства и бит направления.

Сам адрес состоит из семи бит (вот почему до 127 устройств на шине), а восьмой бит означает что будет делать Slave на следующем байте — принимать или передавать данные. Девятым битом идет бит подтверждения ACK. Если Slave услышал свой адрес и считал полностью, то на девятом такте он придавит линию SDA в 0, сгенерировав ACK — то есть Понял! Мастер, заметя это, понимает, что все идет по плану и можно продолжать. Если Slave не обнаружился, прозевал адрес, неправильно принял байт, сгорел или еще что с ним случилось, то, соответственно, SDA на девятом такте будет прижать некому и ACK не получится. Будет NACK. Мастер с горя хлопнет водки и прекратит свои попытки до лучших времен.

После адресного пакета идут пакеты с данными в ту или другую сторону, в зависимости от бита RW в заголовочном пакете.
Вот, например, Запись. В квадратиках идут номера битов. W=0

Чтение практически также, но тут есть одна тонкость из-за которой я когда то убил кучу времени. При приеме последнего байта надо дать ведомому понять, что в его услугах больше не нуждаемся и отослать NACK на последнем байте. Если отослать ACK то после стопа Master не отпустит линию — такой уж там конечный автомат. Так что прием двух байтов будет выглядеть так (R=1):

Есть еще одно состояние, как повторный старт.
Это когда мы не обьявляя STOP вкатываем на шину еще один START. После него мы можем обратиться к другому устройству не освобождая шину. Но чаще идет обращение к тому же самому устройству и это связано с особенностями организации памяти.

Организация памяти.
Это относится уже не столько к самому протоколу I2C, сколько к заморочкам создателей разных EEPROM и прочих I2C устройств. Но встречается это повсеместно, поэтому я расскажу про этот момент. Но, повторюсь, это не аксиома, не стандарт и вообще зависит от конкретного Slave устройства. Так что датит в зубы и вкуривать, но обычно так принято.

Итак, о чем речь.
Как видно из протокола, в первом байте мы адресовываем само устройство, а их может быть до 127 штук. Но в самом устройстве вполне может быть очень сложная структура, с кучей ячеек. Например EEPROM с килобайтами данных внутри. Как обращаться с этими данными? Не считывать же все по очереди от нуля до конца — это долго. Поэтому приняли хитрый формат. Это не стандарт, но юзается повсеместно.

Поясню на примере:
Есть микросхема часов реального времени PCF8583 (я про нее еще напишу, следите за обновлениями), общающася по протоколу I2C. Внутри нее ячейки памяти, в которых хранятся часы, минуты, секунды, дата, состояние флагов и куча еще всего. До кучи там еще 240 байт просто так, для свободного пользования. Карта адресов этой микросхемы выглядит так:


И вот надо мне установить дату. Для этого надо мне записать две ячейки памяти с адресами 0х05 и 0×06. Как это сделать? Из даташита я узнаю, что первый байт данных это адрес куда мы будем обращаться, а потом уже идут данные и со следующим байтом счетчик адреса увеличивается на 1. Там же, в даташите, написано что эти часы откликаются на Slave-адрес 1010000х где х — состояние ноги А0 микросхемы. Я эту ногу сразу посадил на 0 так что Slave-адрес у меня 10100000. Очевидно, что на одной шине может быть не более двух экземпляров этой микросхемы с адресами 10100000 и 10100001.

Задача решается так:

Вот и славно. Часы установлены и начали тикать. Но вот надо нам считать те же данные, а вдруг изменились?
С записью все понятно — записали вначале адрес, а потом следом записали данные. А умная микросхема все прекрасно поняла и рассовала по ячейкам. А с чтением? А с чтением все через задницу, в смысле через запись.

То есть, мы, вначале, записываем один байт — адрес. Потом делаем повторный старт, затем снова обращаемся к часам по ее Slave-адресу, но уже с битом R, на чтение. И умная микруха выдает нам байты с адреса который мы в нее вот только что записали. Выглядит это так:

В этих часах так, у других микрух может быть все по другому, но в 99% очень похоже. Адрес, например, может быть двухбайтным или страницу надо будет указать, но сути это не меняет. Цепочка запись-повстарт-чтение это повсеместно.
Вот так, кстати, выглядит чтение данных из часов PCF8583 на экране моего логического анализатора. Тут не полная посылка (все 5 байт просто не влезли в экран), но тут четко видно запись начального адреса, потом повторный старт, и чтение из девайса.

Скриншот с осциллографа RIGOL 1042CD

Арбитраж шины I2C.
Почему то все мануалы для начинающих в которых рассматривалась тема протокола IIC как то ссыкливо замалчивают возможность работы двух ведущих на линии. Master-Slave и все тут. А если у нас демократия? И каждый сам себе Master и сам себе Slave? Согласен, редкий случай, но тем не менее, описывать так описывать. Короче, в случае подобного садо-мазо варианта действует железное правило — кто раньше встал того и тапки. В смысле кто первый начал вещать тот и текущий Master.

Но вот случилось вообще невероятное — два Ведущих начали вещать одновременно. Прям совсем одновременно. Как быть? А тут нам поможет свойство монтажного И — где против лома нуля нет приема. Короче, оба мастера бит за битом играют в простую игру ножик-камень(1 и 0 соответственно). Кто первый выкинет камень против ножика тот и побеждает арбитраж, продолжая вещать дальше. Так что очевидно, что самый важный адрес должен начинаться с нулей, чтобы тот кто к нему пытался обращаться всегда выигрывал арбитраж. Проигравшая же сторона вынуждена ждать пока шина не освободится.

Вроде бы все, практический пример с AVR будет потом, а пока помедитируйте над диаграммой работы конечного автомата TWI передатчика ATmega8. Скоро я вас буду этим грузить!


Страшна? ;) На самом деле там все не так брутально. Можно обойтись вообще парой десятков строк кода на ассемблере.

UPD:
Полный перевод оригинальной спецификации IIC от суровых Челябинских электронщиков с радиозавода Полет

Запись опубликована в рубрике Начинающим с метками , , , . Добавьте в закладки постоянную ссылку.

107 комментариев: Интерфейсная шина IIC (I2C)

  1. blacklion говорит:

    (1) OpenID работает криво. Я зашёл как blacklion.livejournal.com и всё равно справа-сверху «войти» (а не «выйти») и не даю комментировать. Пришлось регистрироваться и теперь тут два меня.

    (2) Софтового мастера сделать не сложно. А вот слейва как-то просто не получается.

    • DI HALT говорит:

      Щас попробую с опен ид поиграться.

      Более того, многие предпочитают делать софтовый И2С мастер чтобы не заморачиваться с встроенным в TWI конечным автоматом.

      • blacklion говорит:

        Более того, многие предпочитают делать софтовый И2С мастер чтобы не заморачиваться с встроенным в TWI конечным автоматом.
        Я когда первый раз подходил к электронике смотрел на PIC (зачем я это делал!? Зачем на PIC?!) так реализовал мастера в качестве упражнения за вечер. А вот слейва так и не осилил…

    • cahbtexhuk говорит:

      плюсадин. я уже раз 5 жаловался что логины глючат :D нашел выход, что залогинился, пару минуток подождал и рефреш. работает, но бесит :\

  2. KVorb говорит:

    DI HALT спасибо за статью. Давно ждал рассказ про I2C. :)

  3. cahbtexhuk говорит:

    Могу поделицца опытом работы конкретно с DS1307. Он, сука, еще тот глючный девайс. Вроде просто, но не все просто. ПРопиши бит СН, запусти часы, не забудь про бит снова, ой а чо горим — а мы забыли Vbat на землю положить…

    • DI HALT говорит:

      У меня их почти полный аналог ICL12008 ваще работать не хотят — не отзываются на свой адрес, не дают ACK

    • Spirt0 говорит:

      Да, есть такое дело :) Вообще при начале работы с IIC девайсом, желательно вдоль и поперек изучить Datasheet к нему. В свое время тоже поломал голову с m41 от ST. Вроде все пишется, все читается, но часы стоят и все тут. Оказалось там есть хитрый битик, который при пропадании всего питания — Vcc и Vbat, останавливает часы и пока его не сбросишь они не пойдут.
      Ну и еще обычный прикол с часами, что не все могут работать при отключенной батарейке — даже если Vcc есть, внутри у них стоит контроль, который проверяет разницу между напругой и Vbat, и если Vbat нет, то часы просто ни на что не отвечают :)

      p.s. а про NACK в конце чтения это да, самые популярные грабли наверно. Кстати для отлаживания шины если нет крутого осцила, можно прикрутить I2C Sniffer на Atmega8 — оч удобная штука, она в консоли показывает полностью весь обмен в удобоваримом виде.

      • ArgusB говорит:

        А чё с ним было голову ломать? Кстати, m41t56 рекомендую, простые и удобные I2C часы. Про битик я давно знал — он у всех часовых изделий от ST присутствует. Наверное, как совместимость с m48t08 — который с батареей на борту. Чтобы батарею не сажать, пока таймкипер лежит на складе, они глушат часы.

  4. Sniper говорит:

    О)) На самом деле классная тема! Мне бы сначала с простым UARTом разобраться, а потом только к творению Philips)) Буду ждать исходников…

  5. Thi3f говорит:

    Отличная статья! А есть последняя диаграмма только в чуть лучшем качестве? А то буквы трудно различить.

  6. Medved говорит:

    Про 1-Wire напиши еще :-)

  7. ploop говорит:

    >>Ни в коем случае нельзя переключать вывод микроконтроллера в OUT и дергать ногу на +5. Можно запросто словить КЗ и пожечь либо контроллер либо какой-нибудь девайс на шине. Мало ли кто там линию придавит.

    Разговаривали на эту тему с одним человеком. Он мысль сказал — если на каждую микросхему между ней и линией поставить резисторы по 100 Ом, то в принципе, проблема будет решена. Так же удобно при отладке.

  8. Saniok говорит:

    Похожее разрешение коллизий используется в CAN… но там всёже гораздо более сложный протокол.

  9. Ди, можно вопрос? Вот здесь вот ( http://www.gaw.ru/html.cgi/txt/interface/iic/iic_4.htm ) написано, что скорость передачи данных — 100 кбит/с в обычном режиме, у тебя — 10 кбит/с. Кому верить?

  10. Ridik911 говорит:

    спасибс
    ждемс также как работать с SRAM (и dram)
    (кланюсь.. и пока ушел)

  11. rc-dimon говорит:

    Спасибо за очень подробную статью. Хотелось бы очень увидеть такую же по SPI

  12. Ivan говорит:

    «Передача/Прием сигналов осуществляется прижиманием линии в 0, в единичку устанавливается сама, за счет подтягивающих резисторов.»

    PORTx.x = 0; //Прижал в 0

    тут код

    PORTx.x = 1; //Пока так не сделаю, в единицу не устанавливается, подтяжка есть 4k7

    Настройка порта:
    PORTC=0×00;
    DDRC=0xFF;

    И сразу еще один вопрос, как передать в процедуру номер ноги контроллера?
    пробовал так:

    void my_proc(unsigned char _port)
    {
    }

    вызываю так:

    my_proc(PORTB.3) и не работает…

    • DI HALT говорит:

      Ногу надо передавать по отдельности. Т.к. PORTB это адрес порта. А 3 — просто номер пина. Так что либо в две переменные либо просто номер пина, а порт уже прописан в функции. Вот только нафига тебе тут функция? Напрямую то нельзя чтоль?

      • Ivan говорит:

        Не, напрямую нельзя, нога заранее неизвестна (и порт тоже).
        Интересно, если передать номер порта и ноги раздельно, как их потом лучше всего объединить?

        Блин, каша в голове (только учусь) на работу с датчиком ds18b20 как должен быть настроен порт? //Заранее спасибо!

        Разобрался… Proteus 7.4 SP3 с краком 1.6.3 — 6.5 от Nemo глючит сильно …
        скачал 7.5 — ВСЕ СРАЗУ ЗАРАБОТАЛО!! Начинающим, как и я, обновлять обязательно!
        Вопрос по передаче номера ноги в процедуру в силе, буду благодарен за пример.

  13. vados говорит:

    DI HALT Привет! Очень полезна статья, вот недавно наткнулся на убитую магнитолу с микросхемой LC75373(аудиопроцессор), так вот там управление осуществлется, как я понял, что-то наподобие I2C (как написано в datasheet — serial data input). Единственное отличие это не две линии а три — CE, DI и CL. Как я понял управление осуществляется в одну сторону, т.е. только на прием. Вот единственное что я хотел у тебя спросить, возможно ты когда-нибудь сталкивался с подобием такой микрухи, хотел узнать управление происходит только единичной посылкой управления, или возможно как-то по-другому. В datasheet не нашел вразумительного ответа. Конечно вопрос не совсем в тему, но все-таки надеюсь на отклик.

    • DI HALT говорит:

      Это не I2C это почти чистый SPI только в одну сторону.
      Формат данных там написано что 52 бита — 8 адреса и 44 данные.
      Точнее как, вначале СЕ ложишь вниз, подаешь 8 бит адреса. Потом поднимаешь СЕ вверх и гонишь 44 бита данных. В этих 44 битах закодированы параметры для резисторных матриц. Как переслал СЕ бросаешь вниз и при этом происходит запоминание введенных данных.

      Как и что слать там нормально написано.Я бы сказал даже очень наглядно нарисовано. На 15й странице даташита

      • vados говорит:

        Спасибо! В принципе так и думал, единственное что до сих пор не внушает доверие в datasheet так это то что получается СЕ нужно ложить вниз не на 8 бит адреса, а на 9 (или возможно это опечатка), т.е. захватывает старший бит данных D0 (если верить рисунку осцилограммы). Но конечно судя по логике все-таки скорее правильнее как ты написал — СЕ ложишь вниз, подаешь 8 бит адреса.

  14. Cluster говорит:

    Жду примера для AVR, а то у меня как-то руки не дошли разобраться в этом :)

  15. voltAVR говорит:

    Здравствуйте, подскажите как можно организовать контроль I2С шины, если например есть N-ое количество устройств и одно из них придавило линию и например зависло в таком состоянии, есть ли возможность узнать какое программно, а лучше аппаратно отключить его или показать что оно не работает.

  16. SAShA_II говорит:

    Вот интересно. Вопрос, конечно, может и дурацкий. А можно ли сделать программное подобие I2C используя USART? Соединив все TX слейвов с RX мастера и все RX слейвов с TX мастера. Будут ли слейвы все слейвы одновременно принимать данные от мастера или есть какие-то подводные камни в этом? I2C мне не подходит из-за ограничения по количеству устройств.

  17. sseett говорит:

    Прекрасное описание шины. Живой язык, яркие рисунки.
    По моему, в статье есть неточность.
    Автор пишет:
    «Если Slave торомоз и не успевает (у EEPROM, например, низкая скорость записи), то он может насильно положить линию SCL в землю и не давать ведущему генерировать новые такты. Мастер должен это понять и дать слейву прожевать байт. Так что нельзя тупо генерить такты, при отпускании SCL надо следить за тем, что линия поднялась. Если не поднялась, то надо остановиться и ждать до тех пор, пока Slave ее не отпустит. Потом продолжить с того же места.»

    Пример с EEPROM мне показался неудачным, т.к. обычно у них к SCL только вход.
    Вход же не может притянуть SCL к земле.
    Но для многих других I2C микрух этот вариант прокатывает.

    Спасибо автору за труд.

  18. sseett говорит:

    Вы согласны, что вход не может притянуть линию к земле.
    http://www.gaw.ru/pdf/Atmel/at24/AT24C128_256.pdf

    Table 1. Pin Configuration
    Pin Name Function
    A0 — A1 Address Inputs
    SDA Serial Data
    SCL Serial Clock Input -вход
    WP Write Protect
    NC No Connect
    GND Ground

    Смотрите еще Figure 1. Block Diagram
    Там на SDA висит транзистор, а на SCL – нет.
    Если слейв занят внутренними проблемами, то он просто отключается от шины и не реагирует на мастера. Мастер должен отправить условие старта после адресного слова и ждать ответа.
    Вот тут на русском: http://www.gaw.ru/html.cgi/txt/doc/memory/seeprom/at24c128_256.htm

    • DI HALT говорит:

      Да. В самом деле, вы правы. Видимо тут такой подход связан с тем, что запись буффера будет очень долгой чтобы на это время нельзя парализовывать работу шины.

  19. AlexRu1 говорит:

    День добрый. Помогите пожалуйста с ds1307. Уже третий день мучаю ее, запустить не могу — в протеусе работает «как часы»:), а в железе — на экране 2.1.2.1 Осца временно нету, посему пытался проверить путем конфигурации ее на вывод SQW с частотой 1 Гц — генерация отсутствует. Здесь я краем уха слышал по поводу батарейного питания — может у меня в этом проблема??? Вывод Vbat у меня висит в воздухе. Заранее спасибо.

    • DI HALT говорит:

      Без батарейного питания они не стартанут. Либо будут в каком нибудь энергосберегающем режиме висеть. Батарею подцепи, тогда пойдут. Может еще какой регистр внутри надо будет дергнуть. Но это даташит кури.

  20. AlexRu1 говорит:

    Сами часики вроде в норме. Проблема с контроллером (точнее с программой). Я отключил контроллер от часиков, далее запускаю и проверяю осцом что у меня на SDA и SCL. В итоге вообще запутался — идет передача данных, а в перерывах шина лежит в нуле. Почему проц может не отпускать шину???? (чтение данных спецом отрубил — контроллер в режиме мастер-передатчик). И как тут можно выложить кусок кода? может кто-то что-то поможет…А то беда — контроллер весь учу всего пару месяцев, а тут на одной шине i2c зависнул уже на две недели.

    • DI HALT говорит:

      Последний байт NACK?

      • AlexRu1 говорит:

        По поводу NACK:
        Вот тут меня мучает такой вопрос:
        TWCR — он же не буферизированный? Как же тогда в сях одной командой установить TWEN, TWINT и сбросить TWEA (режим NOASK)???
        Я так понимаю — в таком порядке не пройдет:
        TWCR &= ~(1<<TWEA)
        TWCR |= ((1<<TWINT) | (1<<TWEN))

        по идее в обратном:

        TWCR |= ((1<<TWINT) | (1<<TWEN))
        TWCR &= ~(1<<TWEA)

        тоже не должно работать. Ведь и в том и в другом случае мы обнуляем TWINT первой командой и сражу начинается работа модуля.
        Прав я или где-то запутался???

        может так? :

        TWCR &= ~((1<<TWEA) | (1<<TWINT))
        TWCR |= ((1<<TWINT) | (1<<TWEN))

        Но я даже убрал вообще прием — оставил только передачу (инициализация). Когда идет прием — тогда поинтересней. Вот мой маин:

        while(1)
        {
        read_rtc ();
        _delay_ms (500);
        shou_clock ();
        }

        так на осце идет меандр с периодом, который задан в задержке (мс 500) а передача идет коротко на спаде и фронте импульсов. То есть:
        шина в «1!
        чтение
        шина не поднялась
        500 мс
        шина не поднялась
        чтение
        шина в «1″ и тд

        • DI HALT говорит:

          А что тебе мешает сформировать сразу весь байт?

          1
          
          TWCR=(0<<TWEA|1<<TWINT|1<<TWEN);
          • AlexRu1 говорит:

            А разве в WinAVR такой вариант потянет? Как я понимаю — gcc сильно заточен под стандарты языков, а если данную строку разложить, то получим несуразицу…хотя он компилирует. Нет что-то мне кажется, что так можно еще больше запутаться.

          • DI HALT говорит:

            Гхм. Срочно! Учить матчасть!!!

            Вот такая запись для него как раз родней некуда. Обычное присваивание байта байту. ВСЕ.

          • AlexRu1 говорит:

            Я просто не заметил что там = а не |= вот и удивился.

          • AlexRu1 говорит:

            Так а если через бит-маску — какой из трех вариантов канает?

          • DI HALT говорит:

            Через XOR можно сделать обычную инверсионную маску. Только зачем? Присваивай и все.

          • AlexRu1 говорит:

            Суть я уловил. Я в принципе догадывался что надо использовать XOR. Зачем — другой вопрос. Хочу отточить навыки и разобраться со всем (а лог арифметика сюда также входит) и, самое главное, выработать один стиль. Ведь, насколько я знаю, простое присваивание не всегда катит. Нужно следить за всеми регистрами, а для буферизированных — битмаска — что доктор прописал (не пинайте асемблерщики). Вот и пытаюсь на одном примере (раньше взял очередной модуль, написал прогу и пошел дальше, а тут застрял) отточить многие нюансы).

            Еще пара вопросов:
            1) Если я отключил все устройства (оставил один контроллер) — он ведь после всех попыток общение по iic должен отпустить шину??? А резисторы ее притянуть к «1″? Верно?
            2) С какой частотой надо опрашивать RTC, что-бы, как говориться, и волки сыты и овцы целы?

          • DI HALT говорит:

            Чтобы контроллер отпустил шину он должен выйти из конечного автомата. (погляди на диаграмму работы) для этого ему надо получить одно из состояний. Единственно что если ты ТВИ вырубишь вообще, то он должен шину отпустить. Ну а дальше резисторы.

            2) С какой тебе надо с такой и опрашивай. Но, сам понимаешь, нет смысла спрашивать чаще чем меняется самый младший разряд часов. А вообще я его спрашиваю когда надо получить значение. Разово, не циклически. Зачем зря шину занимать?

          • AlexRu1 говорит:

            По поводу первого вопроса:
            Я отключил все на шине TWI. Перевожу контроллер в режим мастер-передатчик, передаю байт и даю команду СТОП. Контроллер при этом должен в любом случае отпустить шину??? В режиме передатчика это условие является абсолютным???

          • DI HALT говорит:

            Не помню. Надо посмотреть на диаграмму переходов.

          • AlexRu1 говорит:

            Все РАБОТАЕТ!!!! Спасибо. Проблема в NACK:
            Заменил
            TWCR &= ~(1<<TWEA)
            TWCR |= ((1<<TWINT) | (1<<TWEN))

            на

            TWCR=(0<<TWEA|1<<TWINT|1<<TWEN);
            и все пошло.

          • AlexRu1 говорит:

            Да, здесь обновляется весь регистр. Так прокатит. А вот бит-маску вроде так не наложить.

          • DI HALT говорит:

            Можно сделать хитрую маску которая инверснет нужные биты. ПО ксору.

  21. AlexRu1 говорит:

    Всем спасибо за помощь.

  22. redradist говорит:

    Вопрос: а можно ли осуществлять по данному протоколу следующие действия:
    Старт, передача адреса устройства + W, передача адреса ячейки, ПОВ-Старт, передача адреса устройства + R, считывание ячейки, считывание следующей ячейки,(вот со следующего действия и начинаются проблемы) ПОВ-Старт, передача адреса устройства + W, передача адреса ячейки, запись одного байта, запись второго байта, СТОП … Моделирую в протеусе, нихера не получается, а до этого все нормально … Помогите …

    • DI HALT говорит:

      считывание ячейки, считывание следующей ячейки, [??????ACK или NACK??????](вот со следующего действия и начинаются проблемы)Повстарт…

      Должен быть NACK иначе линию не отдаст.

  23. redradist говорит:

    DI HALT, уже делал НАК, он передает, но результат на индикаторах не тот … ((((

  24. Stydent говорит:

    DI HALT, посоветуй пожалуйста! ломаю голову не знаю какой интерфейс выбрать IIC или SPI для связи 17 МК(каждый принимает и передает).

  25. Stydent говорит:

    DI HALT, подскажи пожалуйста, а что будет происходить, если в момент передачи информации возникнет не запрещенное прерывание в ведущем передающем МК? и 2-й вопрос если связь будет прост оборвана, сохранятся ли в ведомом приемнике, успевшие прийти до прерывания,байты?

    • DI HALT говорит:

      Смотря как реализован мастер. Если аппаратно, то он дошлет текущий байт и выставит нужные уровни сам. Просто передача чуток встрянет на время обработки прерывания. ИИС это же синхронная шина и остановка мастера дает лишь остановку передачи, а не срыв передачи.

  26. Stydent говорит:

    DI HALT, помоги разобраться, после каждой операции модулем TWI устанавливает флаг TWINT, дальше необходимо проверить код статуса (размер 1байт), на сколько я понял этот код надо искать в регистре TWSR в пяти битах TWS. Как может хранится код $38 в пяти битах ?

    • DI HALT говорит:

      Почему в пяти битах?

      • Stydent говорит:

        Регистр TWSR состоит из след. битов: 0-1 — это коэф деления предделителя,2 — зарезервирован, 3-7 — биты состояния модуля TWI (5 битов TWS). В TWS должен же хранится код статуса, или нет?

        • DI HALT говорит:

          2 может и зарезервирован, но он все равно читается как 0. Обрати внимание, все коды имеют в младшем разряде 0. Это и есть этот зарезервированый бит.

          Так что просто сдвигаешь вправо на два бита значение TWSR и вот тебе код статуса.

  27. mmm говорит:

    Очень доходчиво! Коротко и понятно. Огромное спасибо за популярное объяснение. Читал 2 дня официалку — недопер). Дым из башки валит а понимания «0″.

  28. kingdomof говорит:

    Здравствуйте!
    Можно ли связать через интерфейс I2C (TWI) несколько МК Attiny13 (Slave) и Atmega64 (Master)? Если нет то, какие интерфейсы лучше использовать?

      • kingdomof говорит:

        Разве в данном случае не обязательно чтобы Attiny13 поддерживал I2C (TWI), т.к. в даташите нету информации, что они поддерживают TWI.

        Проблема в том что, я думаю что если использовать I2C, то те приборы (датчики и т.п.) которые подключаются к этой шине должны поддерживать I2C.

  29. DI HALT говорит:

    Если в контроллере чего то нет это всегда можно сделать программно. Хотя I2C Slave программно сделать сложно, но можно. Ну и придется все писать на ассемблере и очень жоско оптимизировать, т.к. памяти там совсем мало. Есть другие 8ми ножки с большим числом памяти (Тини88) с ними будет проще.

    • kingdomof говорит:

      По твоему совету поискал ATtiny88 в http://www.chip-dip.ru, но не нашел. Подскажи, плиз что лучше использовать из дешевых МК для I2C в стиле Plug&Play

      • DI HALT говорит:

        Да я прогнал. Я имел ввиду тини25/45/85 (они различаются только числом памяти) У него не совсем полная поддержка TWI, а скорей полуфабрикат — USI, но самую сложную задачу: ловлю стартов/стопов на slave и отлов байтов аппаратно он тебе сделает.

        Самый же дешевый из тинек, пожалуй это Тини2313 но она на 20 ног.

  30. maze говорит:

    А если сделать несколько модулей с подтяжкой на каждом, то будет ли работать система с включеными нескольками модулями?

  31. SergeyB говорит:

    Режим fast 400kbit/s подразумевает 400 Кгц по линии SCL или же 400кбит чистой информации в секунду?

  32. SergeyB говорит:

    ага, т.е. 400кбит/с означает что за секунду проходит:
    (кол-во старт битов)+(количество стоп битов)+(кол-во Ack/Nack)+(кол-во бит данных)=400кбит

  33. vlad49 говорит:

    Прочитал на твоём сайте статью про 1 wire протокол. Самая понятная и доходчивая из тех что я знаю. Сегодня хотел поделиться инфой с другом и не смог найти.Третий час рыскаю по сайту. Помоги, подскажи где она?

  34. Alesandr говорит:

    Кто каритнки рисовал? В некоторых стоповый бит выделен цветом а по уровням невпопад.

  35. AleksanderG говорит:

    DI HALT большая просьба. Открыть (написать) тему про работу SD карты и МЕГи 32.
    Подключение, обмен, исходный код для обучения (желательно на ассемблере), в общем
    все так, как ты это делаешь доходчиво и со вкусом.

  36. d-lun говорит:

    DI, большое спасибо за диаграмму состояний автомата I2C! Сразу доходит, как все работает.

  37. valio говорит:

    > .. Схема подключения — монтажное И.

    Почему «И» не пойму ? Косяк, это т.н. монтажное «ИЛИ» назвается или «wired OR».
    То бишь А V В в записи или еще есть такое слово — дизъюнкция, или логическое «ИЛИ», иногда включающее «ИЛИ», еще обзывают как логическим сложение, чаще просто «ИЛИ».

    А насчет 100R резюков в сигнальной шине перед слейвом, де-факто прописано в многих апнотах по iic, тот же STM если посмотреть.

  38. buddah говорит:

    Здравствуйте!

    Работаю с PIC16Fxxx,I2C программный, работает !!!, как на чтение, так и на запись, с этим порядок.И все,вроде бы просто —

    lab
    call read_rtc ;чтение DS1307.
    call display ;отображение прочитанного (динамическая индикация).
    goto lab

    , но при таком варианте — на дисплее одна динамическая белеберда.
    А вот если читаю RTC один раз, а отображение в цикле, то все нормуль.
    И паузы втыкал после call read_rtc и регистры чистил после call display (нафиг, правда не понятно…). В общем, RTC тикают,правильно тикают,а читать могу ОДИН, блин, раз. Понятное дело, чтение будет по прерыванию, но блин, чего оно не читается в цикле..? Может кто-то сталкивался с такой какой, помогите плиз. (…а инета скока перерыл, ниче подобного не нашел.)

  39. ArxangelRUS говорит:

    Про бит подтверждения А. Как то странно работает, он что инверстно пашет? т.е. если посылка удалась, то ведомый на линии не выставляет высокого уровня?

  40. Orienta говорит:

    Эх, DI HALT, как же мне нравится Ваша манера объяснять и непринужденный язык. Читаю сайт как произведение искусства :-)

Добавить комментарий