Безопасность        05.02.2024   

Передача данных. Протокол I2C

В современной бытовой технике, промышленной электронике и различном телекоммуникационном оборудовании достаточно часто можно встретить аналогичные решения, хотя изделия могут быть практически не связаны между собой. К примеру, практически каждая система включает в себя следующее:

  • определенный «умный» узел управления, который в преимущественном большинстве случаев представляет собой однокристалльную микроЭВМ;
  • узлы общего назначения наподобие буферов ЖК, ОЗУ, портов ввода/вывода, ЭСПЗУ или же специализированные преобразователи данных;
  • специфические узлы, включающие в себя схемы цифровой настройки и обрабатывания сигналов для видео- и радиосистем.

Как оптимизировать их применение?

Чтобы обеспечить максимально эффективное использование таких общих решений для выгоды конструкторов и самих производителей, а также для повышения общей степени производительности различной аппаратуры и упрощения применяемых схемотехнических узлов, компания Philips задалась целью разработать предельно простую двухпроводную двунаправленную шину, обеспечивающую наиболее продуктивное межмикросхемное управление. Данная шина обеспечивает через интерфейс I2C.

На сегодняшний день ассортимент указанного производителя включает в себя более 150 КМОП, а также биполярных устройств, совместимых с I2C и предназначенных для ведения работы в любых перечисленных категориях. При этом стоит отметить, что интерфейс I2C является изначально встроенным во все совместимые устройства, за счет чего они и могут безо всяких сложностей поддерживать связь между собой при использовании специальной шины. За счет применения такого конструкторского решения получилось решить достаточно большое количество проблем сопряжения различного оборудования, что является довольно характерным для сферы разработки цифровых систем.

Основные преимущества

Даже если посмотреть кратко SPI, I2C, можно выделить следующие преимущества последнего:

  • Для работы нужно всего две линии - синхронизации и данных. Любое устройство, которое подключается к такой шине, в дальнейшем может программно адресоваться по абсолютно уникальному адресу. В любой момент существует простое отношение, позволяющее ведущим работать в качестве ведущего-передатчика или ведущего-приемника.
  • Данная шина предусматривает возможность иметь сразу несколько ведущих, предоставляя все необходимые средства для определения коллизий, а также арбитраж, позволяющий предотвратить повреждение данных в том случае, если два или большее количество ведущих начинает одновременно передавать информацию. В стандартном режиме предусматривается только передача последовательных восьмибитных данных при скорости не более 100 кбит/с, а в быстром режиме этот порог может быть увеличен в четыре раза.
  • В микросхемах используется специальный встроенный фильтр, который достаточно эффективно подавляет всплески и обеспечивает максимальную целостность данных.
  • Предельно возможное количество микросхем, которые могут быть подсоединены к одной шине, ограничивается только ее предельно возможной емкостью, составляющей 400 пФ.

Преимущества для конструкторов

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

Есть масса преимуществ, которые выделяют интерфейс I2C. Описание, в частности, позволяет увидеть следующие достоинства для конструкторов:

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

Помимо всего прочего, стоит отметить предельно простую процедуру диагностики возникших сбоев и дальнейшую отладку, которой отличается интерфейс I2C. Описание говорит о том, что при необходимости можно безо всякого труда моментально отслеживать даже незначительные отклонения в работе такого оборудования и, соответственно, принимать соответствующие меры. Также стоит отметить, что конструкторы получают специальные решения, которые, в частности, являются довольно привлекательными для различного портативного оборудования и систем, предусматривающих батарейное питание, используя I2C интерфейс. Описание на русском также указывает на то, что его применение позволяет обеспечить следующие немаловажные достоинства:

  • Достаточно высокую степень устойчивости к любым возникающим помехам.
  • Предельно низкое потребление энергии.
  • Широчайший диапазон питающего напряжения.
  • Широкий температурный диапазон.

Преимущества для технологов

Стоит отметить, что не только конструкторы, но и технологи достаточно часто в последнее время начали использовать специализированный I2C интерфейс. Описание на русском указывает довольно широкий диапазон достоинств, которые обеспечиваются этой категории специалистов:

  • Стандартная двухпроводная последовательная шина с таким интерфейсом позволяет минимизировать соединения между микросхемами, то есть в них присутствует меньше контактов и требуется меньшее количество дорожек, благодаря чему печатные платы становятся не такими дорогими и имеют гораздо меньшие габариты.
  • Полностью интегрированный I2C интерфейс LCD1602 или какой-то другой вариант полностью устраняет необходимость в использовании дешифраторов адреса, а также другой внешней мелкой логике.
  • Предусматривается возможность использования одновременно нескольких ведущих на такой шине, благодаря чему существенно ускоряется тестирование и последующая настройка оборудования, так как шина может быть подключена к компьютеру сборочной линии.
  • Доступность совместимых с этим интерфейсом микросхем в VSO, SO и специализированном DIL-корпусе позволяет существенно снизить требования к размеру устройства.

Это только краткий список преимуществ, которыми отличается I2C интерфейс LCD1602 и другие. Кроме того, совместимые микросхемы позволяют значительно увеличить гибкость используемой системы, обеспечивая предельно простое конструирование различных вариантов оборудования, а также относительно легкую модернизацию для дальнейшей поддержки разработки на современном уровне. Таким образом, можно разработать целое семейство различного оборудования, используя в качестве основы определенную базовую модель.

Дальнейшая модернизация оборудования и расширение его функций могут осуществляться посредством стандартного подключения к шине соответствующей микросхемы, использующей 2C интерфейс Arduino или какой-нибудь другой из доступного перечня. Если требуется обеспечение большей ПЗУ, то в таком случае достаточно будет только выбрать другой микроконтроллер, имеющий увеличенный объем ПЗУ. Так как обновленные микросхемы при необходимости способны полностью заместить старые, можно запросто добавлять новые свойства в оборудование или повышать его общую производительность посредством обычного отсоединения уже устаревших микросхем и дальнейшей замены их на более новое оборудование.

ACCESS.bus

За счет того, что шина имеет двухпроводную природу, а также возможность программной адресации, для ACCESS.bus одной из наиболее идеальных платформ является именно I2C интерфейс. Спецификация (описание на русском представлено в статье) данного устройства делает его гораздо более дешевой альтернативой активно использующемуся ранее интерфейсу RS-232C для подсоединения различной периферии к компьютерам, используя стандартный четырехконтактный коннектор.

Введение в спецификацию

Для современных приложений 8-битного управления, в которых используются микроконтроллеры, предусматривается возможность установки некоторых конструкторских критериев:

  • полная система в преимущественном большинстве случае включает в себя один микроконтроллер и прочие в том числе память и всевозможные порты ввода/вывода;
  • общая стоимость объединения различных устройств внутри одной системы должна быть предельно минимизирована;
  • система, на которую возлагаются функции управления, не предусматривает необходимость в обеспечении высокоскоростной передачи информации;
  • общая эффективность непосредственно зависит от выбранного оборудования, а также от природы соединяющей шины.

Для разработки системы, полностью соответствующей перечисленным критериям, нужно использовать шину, в которой будет использоваться последовательный интерфейс I2C. Несмотря на то что в последовательной шине нет пропускной способности параллельных, ей требуется меньшее количество соединений, а также меньше контактов микросхем. При этом не стоит забывать о том, что шина включает в себя не только соединяющие провода, но еще и различные процедуры и форматы, необходимые для обеспечения связи внутри системы.

Устройства, для связи которых используется программная эмуляция интерфейса I2C или соответствующая шина, должны иметь определенный протокол, который позволяет упредить различные возможности столкновений, потери или же блокирования информации. У быстрых устройств должна быть возможность связаться с медленными, и при этом система не должна зависеть от подключенного к ней оборудования, так как в противном случае все улучшения и модификации не смогут быть использованы. Также нужно разрабатывать процедуру, с помощью которой реально установить, какое конкретно устройство на данный момент обеспечивает управление шиной и в какой момент времени. Помимо этого, если различные устройства, имеющие разные тактовые частоты, подключены к одной шине, нужно определиться с источником ее синхронизации. Всем этим критериям соответствует I2C интерфейс для AVR и любые другие из этого перечня.

Основная концепция

Шина I2C может поддерживать любые использующиеся технологии изготовления микросхем. Интерфейс I2C LabVIEW и другие аналогичные ему предусматривают использования двух линий для переноса информации - данных и синхронизации. Любое устройство, подключенное таким образом, распознается за счет уникального адреса вне зависимости от того, идет ли речь о ЖКИ-буфере, микроконтроллере, памяти или интерфейсе клавиатуры, и при этом может работать в качестве приемника или передатчика в зависимости от того, для чего конкретно предназначается данное оборудование.

В преимущественном большинстве случаев ЖКИ-буфер представляет собой стандартный приемник, а память может не только принимать, но и передавать различные данные. Помимо всего прочего, по процессу перемещения информации приборы можно классифицировать как ведомые и ведущие.

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

Интерфейс связи I2C предусматривает наличие сразу нескольких ведущих, то есть более чем одно устройство, способное осуществлять управление шиной, способно к ней подключаться. Возможность использования более одного микроконтроллера в одной шине говорит о том, что более чем от одного ведущего может осуществляться пересылка в определенный момент времени. Чтобы устранить потенциальный хаос, который рискует появиться при возникновении такой ситуации, разработана специализированная процедура арбитража, которую использует I2C интерфейс. Расширители и другие приборы предусматривают подключение устройств к шине по так называемому правилу монтажного И.

Генерация синхросигнала представляет собой обязанность ведущего, и каждый из них вырабатывает собственный сигнал в процессе пересылки данных, и в дальнейшем он может изменяться только в том случае, если его «вытягивает» медленное ведомое устройство или другое ведущее при возникновении столкновения.

Общие параметры

Как SCL, так и SDA представляют собой двунаправленные линии, которые подключаются к положительному источнику питания при помощи подтягивающего резистора. Когда шина оказывается абсолютно свободной, каждая линия пребывает в высоком положении. Выходные каскады устройств, которые подключены к шине, должны быть с открытым стоком или открытым коллектором, чтобы могла обеспечиваться функция монтажного И. Информация через I2C интерфейс может передаваться при скорости не более 400 кбит/с в быстром режиме, в то время как в стандартном скорость не превышает 100 кбит/с. Общее же количество устройств, которые могут быть одновременно подключены к шине, зависит только от одного параметра. Это емкость линии, составляющая не более 400 пф.

Подтверждение

Подтверждение представляет собой обязательную процедуру в процессе передачи данных. Ведущий генерирует соответствующий импульс синхронизации, в то время как передатчик отпускает линию SDA в течение данного синхроимпульса как подтверждение. После этого приемник должен обеспечить стабильное удержание линии SDA в течение высокого состояния синхроимпульса в стабильно низком состоянии. В данном случае нужно обязательно принимать во внимание время установки и удержания.

В преимущественном большинстве случаев адресованный приемник должен в обязательном порядке сгенерировать подтверждение после каждого полученного байта, и единственным исключением здесь являются только те ситуации, когда начало посылки включает в себя адрес CBUS.

Если у ведомого-приемника нет возможности отправить подтверждение собственного адреса, нужно оставлять линию данных в высоком состоянии, и после этого у ведущего будет возможность выдачи сигнала "Стоп", который прервет отправку всей информации. Если же адрес был подтвержден, но при этом ведомый не может в течение длительного времени больше принимать какие-либо данные, ведущим также должна быть прервана посылка. Чтобы это сделать, ведомый не подтверждает следующий полученный байт и просто оставляет линию данных в высоком состоянии, вследствие чего ведущим генерируется сигнал "Стоп".

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

Чтобы проверить работоспособность оборудования, можно попробовать ввести стандартные примеры скетчей для интерфейса I2C в Arduino, как на фото выше.

Арбитраж

Ведущим может начинаться пересылка информации только после полного освобождения шины, но при этом два и более ведущих могут провести генерирование сигнала о старте при времени минимального удерживания. Это в конечном итоге приводит к определенному сигналу "Старт" на шине.

Работа арбитража осуществляется на шине SDA в те моменты, пока SCL-шина пребывает в высоком состоянии. Если один из ведущих начинает передавать на линию данных низкий уровень, но при этом другой - высокий, то последний полностью отключается от нее, потому что состояние SDL является не соответствующим высокому состоянию его внутренней линии.

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

Если ведущий проигрывает арбитраж, то в таком случае он может выдавать импульсы синхронизации в SCL до конца байта, в течение которого и был потерян доступ.

Которая применила его для организации связи между микросхемами в своих телевизорах. I 2 C (аббревиатура слов Inter-Integrated Circuit), и представляет собой двунаправленную асинхронную шину с последовательной передачей данных. Физически шина I 2 C представляет собой две сигнальные линии, одна из которых (SCL) предназначена для передачи тактового сигнала, а вторая (SDA) для обмена данными. Для управления линиями применяются выходные каскады с открытым коллектором, поэтому линии шины должны быть подтянуты к источнику питания +5 В через резисторы сопротивлением 1...10 кОм, в зависимости от физической длины линий и скорости передачи данных. Длина соединительных линий в стандартном режиме может достигать 2-х метров, скорость передачи данных - 100 кбит/с.

Все абоненты шины делятся на два класса - "Master" и "Slave". Устройство "Master" генерирует тактовый сигнал (SCL) и, как следствие, является ведущим. Оно может самостоятельно выходить на шину и адресовать любое "Slave"-устройство с целью передачи или приёма информации. Все "Slave"-устройства "слушают" шину на предмет обнаружения собственного адреса и, распознав его, выполняют предписываемую операцию. Кроме того, возможен так называемый "MultiMaster"-режим, когда на шине установлено несколько "Master"-абонентов, которые либо совместно разделяют общие "Slave"-устройства, либо попеременно являются то "Master"-устройствами, когда сами инициируют обмен информацией, то "Slave", когда находятся в режиме ожидания обращения от другого "Master"-устройства. Режим "MultiMaster" требует арбитража и распознавания конфликтов. Естественно, он сложнее в реализации (имеется ввиду программная реализация) и, как следствие, реже используется в реальных изделиях.

В начальный момент времени - в режиме ожидания - обе лини SCL и SDA находятся в состоянии лог. 1 (транзистор выходного каскада с открытым коллектором закрыт). В режиме передачи (рисунок 1) бит данных SDA стробируется положительным импульсом SCL. Смена информации на линии SDA производится при нулевом состоянии линии SCL. "Slave"-устройство может "придерживать" линию SCL в нулевом состоянии, например, на время обработки очередного принятого байта, при этом "Master"-устройство обязано дождаться освобождения линии SCL, прежде чем продолжать передачу информации.


Рисунок 1 - Диаграмма процесса передачи данных по шине I 2 C

Для синхронизации пакетов шины I 2 C различают два условия - "START" и "STOP", ограничивающие начало и конец информационного пакета (рисунок 2). Для кодирования этих условий используется изменение состояния линии SDA при единичном состоянии линии SCL, что недопустимо при передаче данных. "START"-условие образуется при отрицательном перепаде линии SDA, когда линия SCL находится в единичном состоянии, и наоборот, "STOP"-условие образуется при положительном перепаде линии SDA при единичном состоянии линии SCL.



Рисунок 2 - Диаграмма "START" / "STOP" условий шины I 2 C

Передача данных начинается по первому положительному импульсу на линии SCL, которым стробируется старший бит первого информационного байта. Каждый информационный байт (8 битов) содержит 9 тактовых периодов линии SCL. В девятом такте устройство-получатель выдаёт подтверждение (ACK ) - отрицательный импульс, свидетельствующий о "взаимопонимании" передатчика и получателя. Следует отметить, что любой абонент шины, как "Master", так и "Slave" может в разные моменты времени быть как передатчиком, так и получателем и в соответствии с режимом обязан либо принимать, либо выдавать сигнал ACK , отсутствие которого интерпретируется как ошибка.

Чтобы начать операцию обмена, устройство "Master" выдаёт на шину "START"-условие, за которым следует байт с адресом "Slave"-устройства (рисунок 3), состоящий из семибитового адреса устройства (биты 1...7) и однобитового флага операции - "R/W " (бит 0), определяющего направление обмена, причём 0 означает передачу от "Master" к "Slave" (рисунок 3а), а 1 - чтение из "Slave" (рисунок 3б). Все биты по шине I 2 C передаются в порядке старший-младший, то есть первым передаётся 7-ой бит, последним 0-ой. За адресом могут следовать один или более информационных байтов (в направлении, определённом флагом R/W ), биты которых стробируются сигналом SCL из "Master"-устройства.

При совершении операции чтения "Master" абонент должен сопровождать прочитанный байт сигналом ACK , если необходимо прочитать следующий байт, и не выдавать сигнал ACK , если собирается закончить чтение пакета (см. рисунок 3б).

Допускается многократное возобновление "Slave"-адреса в одном цикле передачи, то есть передача повторного "START"-условия без предварительного "STOP"-условия (рисунок 3в).



Рисунок 3 - Формат операций чтения/записи

Необходимо отметить некоторые особенности микросхем памяти, работающих по интерфейсу I 2 C, и процедур обмена данными с ними. Во-первых, энергонезависимая память данных этих микросхем разбита на страницы памяти, поэтому при записи байта вначале происходит копирование всей страницы во внутреннюю оперативную память микросхемы, где производится изменение нужной ячейки. После этого, производится стирание старой страницы и запись на её место новой. Ещё одной особенностью является то, что старшие четыре бита адреса "Slave" всегда должны быть равны 1010. Это требование регламентировано самой фирмой Philips.

Теперь рассмотрим процедуры "общения" ведущего с микросхемой памяти. Прежде всего, он обязан сформировать на шине условие "START", вслед за которым послать байт с адресом ведомого и установленным признаком записи. Получив подтверждение приёма, ведущий продолжает передачу, посылая один или два байта адреса (зависит от ёмкости микросхемы) ячейки памяти. Приём каждого из них должен быть подтверждён "Slave"-устройством. В отличие от привычного программистам принятого в IBM PC порядка первым в данном случае передаётся байт со старшими разрядами адреса.

Дальнейшие действия зависят от того, намерен ли ведущий читать данные, хранящиеся в массиве памяти ведомого, или записывать их туда. Для записи одного или нескольких байтов их достаточно передать вслед за адресом. Первый попадёт в заданную ячейку, после чего внутренний контроллер микросхемы памяти автоматически инкрементирует адрес. Поэтому повторять его передачу не требуется. Следующий байт будет направлен в следующую ячейку и так далее до верхней границы страницы записи (в соответствующем числе младших разрядов адреса ячейки - все единицы), после чего заполнение страницы продолжится с нижней границы (в младших разрядах - все нули). Число байт данных, передаваемых в одном сеансе, не ограничено, но сохранятся лишь последние из них в количестве, не превышающем длины страницы.

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

В любом случае после передачи и подтверждения приёма всех данных для программирования ведущий подаёт команду "STOP", запускающую в микросхеме внутренний автомат записи. Время записи здесь довольно большое - около 10 мс. Если данные переданы в мультибайтном режиме и находятся на разных страницах, продолжительность записи удваивается - автомат программирует две страницы.

До окончания процедуры программирования микросхема памяти не реагирует ни на какие внешние сигналы и в течение этого времени на повторные обращения ведущего по её адресу не откликается. Этим пользуются для определения момента завершения программирования.

Перед чтением данных не требуется обязательно указывать адрес ячейки. Если ведущий обращается к микросхеме памяти, установив в младшем бите байта адреса "Slave" признак чтения, в ответ ему будет передан байт из ячейки, следующей за той, с которой выполнялась последняя операция записи или чтения, после чего счётчик адреса будет автоматически инкрементирован. Продолжая посылать импульсы SCL, ведущий может последовательно и неоднократно прочитать весь массив данных. Возврата к началу страницы на её границе при чтении не происходит, а за адресом последней ячейки всего массива следует нулевой. Сигнал окончания чтения - отсутствие подтверждения ведущим приёма последнего или единственного байта данных и следующая за этим команда "STOP".

При необходимости адрес читаемой ячейки задают в явном виде следующим образом (см. рисунок 3в). Прежде всего, ведущий обращается к микросхеме памяти с признаком записи и посылает ему один или два байта адреса ячейки. Получив подтверждение, он немедленно посылает новую команду "START", а за ней - адрес "Slave" с признаком чтения и выполняет описанную выше процедуру. Первым ему будет передан байт из ячейки с указанным адресом.

Все вышеописанные процедуры обмена данными относятся и к микросхемам часов реального времени, за исключением того, что некоторые ячейки памяти у них представляют собой регистры счётчиков даты времени и, соответственно, изменяются самой микросхемой, хотя ничто не запрещает изменять их и ведущему (так производится установка времени).

Удобства применения шины I 2 C очевидны - малое количество соединительных линий и высокая скорость обмена, простота аппаратной реализации линии связи. Наиболее широко поддерживает шину I 2 C, конечно же, фирма Philips, производящая множество микросхем различной сложности с управлением по I 2 C. В первую очередь, можно выделить микросхемы энергонезависимой памяти (EEPROM) серии 24Схх в 8-ми выводных корпусах, фактически ставшие промышленным стандартом. Из широко распространенных микросхем можно выделить: микросхемы часов DS1307 и DS3231, параллельный порт PCF8574, 4-х канальный 8-ми разрядный АЦП PCF8591.

I 2 C-абоненты жёстко разделяются по классам: "Master"- и "Slave"- устройство. Тот факт, что сигнал SCL всегда генерируется "Master"-устройством означает, что "Master"-абонент может быть достаточно легко реализован чисто программными средствами, так как все изменения на шине будут происходить только по сигналу SCL. И наоборот, реализация "Slave"-устройства требует аппаратной поддержки, кроме случая очень низких скоростей обмена. Существуют однокристальные микроконтроллеры (МК) поддерживающие "Slave"-операции шины I 2 C. Это прежде всего Philips PCF80C552 (652), Microchip PIC16F88 (PIC16F690, PIC18F2620 и др.), Motorola MC68HC705CJ4 (BD3, E5).

Типичная ошибка при реализации программ "Master"-абонента - управление значением порта МК для установки состояний лог. 0 и лог. 1 линий SCL и SDA. Если для МК семейства MCS-51 это нормальный режим работы, так как единичное состояние порта у них реализуется встроенным подтягивающим резистором, то для МК с симметричными портами (Motorola 68HCxx, Microchip PIC, Atmel AVR) это будет порождать электрические конфликты. Например, в руководстве "Microchip. Embedded Control Handbook 1994/1995" приведены практические программы для связи PIC c EEPROM 24Cxx, содержащие подобные грубые ошибки. Положение усугубляется ещё и тем, что в случае микросхем EEPROM такой вариант может сработать, так как они являются 100% аппаратными схемами и не вносят задержек в связной протокол, а паузу ожидания окончания цикла программирования производят переходом в пассивное состояние. Однако использование таких подпрограмм с микросхемами, производящими захват линии SCL (практически любой "Slave"-абонент, реализованный с применением МК), приведёт к невозможности связи, а возможно, и к выходу микросхемы из строя.

Реализовать настоящую имитацию режима "Открытый коллектор" (ОК) (мы назвали этот режим имитацией ОК, так как он не позволяет устанавливать на линии напряжение выше напряжения питания, что было бы нормально для настоящего ОК, но так как по спецификации I 2 C напряжение на линиях SCL и SDA не должно превышать напряжение питания, его вполне законно можно считать выходом с ОК) на порте с симметричным выходом можно, если установить значение порта постоянно в лог. 0, а управлять состоянием линии через манипуляции с регистром направления данных. Для МК семейства PIC это будет регистр "TRISx", переводящий порт либо в третье состояние, либо подключающий линии в соответствии с состоянием регистра "PORTx". Практически так же это реализуется в МК AVR и MC68HC05 (08, 11), где "DDRx" коммутирует порт "PORTx", с той лишь разницей, что у них другая полярность управляющего сигнала - у PIC лог. 0 в "TRISx" соответствует лог. 0 на выходе, а у AVR и MC68HC05 лог. 1 в "DDRx" соответствует лог. 0 на выходе.

Другая важная сторона вопроса - необходимость тщательного соблюдения параметров временной диаграммы процесса обмена. Несмотря на то, что шина I 2 C асинхронная и позволяет затягивать передачу бита (байта) на сколь угодно длительное время (это свойство позволяет реализовывать программы I 2 C-обмена на самом низком уровне приоритета, прерывая процесс передачи в любое время), требования к минимальным значениям длительностей импульсов очень жёсткие. Ситуация усугубляется тем, что положительные перепады состояния линии имеют склонность затягиваться, так как несимметричные управляющие выходы не могут создать крутые положительные фронты.

При написании программ очень важно контролировать время между операциями на шине, реализуемыми различными подпрограммами, например выдача "START" и "STOP"-условия, передача бита, передача байта. При состыковке этих подпрограмм не должны быть нарушены минимальные значения времени, что очень легко происходит при использовании высокоскоростных процессоров (AVR, PIC). Кроме того, необходимо следить, чтобы время между изменением на линии SDA и стробированием положительным импульсом на линии SCL было не меньше половины минимальной длительности полупериода SCL (2,4 мкс для скорости 100 кБит/сек). Помимо этого, некоторые "Slave"-приборы могут ужесточить требования к максимальной частоте обмена, в этом случае необходимо пропорционально снижению частоты обмена увеличивать значения минимумов временных допусков.

Ещё одна распространенная ошибка - игнорирование требования слежения за захватом линии SCL "Slave"-абонентом. Грамотно реализованные прграммы операций "Master"-абонента должны контролировать возврат линии SCL после того, как переводят её в единичное состояние, и только дождавшись реальной установки линии SCL в единичное состояние продолжать операции приемо-передачи.

I2C (Inter-Integrated Circuit ) — последовательная шина данных для связи интегральных схем, использующая две двунаправленные линии связи (SDA и SCL). Используется для соединения низкоскоростных периферийных компонентов с материнской платой, встраиваемыми системами и мобильными телефонами.
Иногда эту шину называют "квадратичной" или "квадратной" или "Ай-Ту-Си"

Принцип работы:

Микроконтроллер на рисунке это ведущий элемент (Master1) им может быть процессор. На рисунке представлено 3 ведомых перефириных элемента Slave В качествеSlave могут быть память, ЦАП, АЦП и пр. К шине может быть подключено до 127 устройств.

Процессор с памятью соединен в данном случае по двум шинам:
SDA (Serial DATA)- шина последовательной передачи данных. Данные по этой шине могут передаваться в двух направлениях.
SCL (Serial Clock) - шина по которой идет тактирование шины данных. Шина синхронизации данных. Она также определяет в какой момент куда пойдут данные. В схеме Master-Master первым битом определяется, кто займет главную роль.
Скорость передачи данных . Так как передаются по 1 биту за 1 такт, то скорость передачи данных составляет 1/8 от тактовой частоты.

Состояние СТАРТ и СТОП
Процедура обмена начинается с того, что ведущий формирует состояние СТАРТ: генерирует переход сигнала линии SDA из ВЫСОКОГО состояния в НИЗКОЕ при ВЫСОКОМ уровне на линии SCL. Этот переход воспринимается всеми устройствами, подключенными к шине, как признак начала процедуры обмена. Генерация синхросигнала — это всегда обязанность ведущего; каждый ведущий генерирует свой собственный сигнал синхронизации при пересылке данных по шине. Процедура обмена завершается тем, что ведущий формирует состояние СТОП — переход состояния линии SDA из низкого состояния в ВЫСОКОЕ при ВЫСОКОМ состоянии линии SCL. Состояния СТАРТ и СТОП всегда вырабатываются ведущим.
Считается, что шина занята после фиксации состояния СТАРТ. Шина считается освободившейся через некоторое время после фиксации состояния СТОП. При передаче посылок по шине I²C каждый ведущий генерирует свой синхросигнал на линии SCL. После формирования состояния СТАРТ ведущий опускает состояние линии SCL в НИЗКОЕ состояние и выставляет на линию SDA старший бит первого байта сообщения. Количество байт в сообщении не ограничено. Спецификация шины I²C разрешает изменения на линии SDA только при НИЗКОМ уровне сигнала на линии SCL. Данные действительны и должны оставаться стабильными только во время ВЫСОКОГО состояния синхроимпульса. Для подтверждения приёма байта от ведущего-передатчика ведомым-приёмником в спецификации протокола обмена по шине I²C вводится специальный бит подтверждения, выставляемый на шину SDA после приёма 8 бита данных.
Подтверждение
Таким образом передача 8 бит данных от передатчика к приёмнику завершаются дополнительным циклом (формированием 9-го тактового импульса линии SCL), при котором приёмник выставляет низкий уровень сигнала на линии SDA, как признак успешного приёма байта.

Подтверждение при передаче данных обязательно, кроме случаев окончания передачи ведомой стороной. Соответствующий импульс синхронизации генерируется ведущим. Передатчик отпускает (переводит в ВЫСОКОЕ состояние) линию SDA на время синхроимпульса подтверждения. Приёмник должен удерживать линию SDA в течение ВЫСОКОГО состояния синхроимпульса подтверждения в стабильном НИЗКОМ состоянии.

В том случае, когда ведомый-приёмник не может подтвердить свой адрес (например, когда он выполняет в данный момент какие-либо функции реального времени), линия данных должна быть оставлена в ВЫСОКОМ состоянии. После этого ведущий может выдать состояние СТОП для прерывания пересылки данных. Если в пересылке участвует ведущий-приёмник, то он должен сообщить об окончании передачи ведомому-передатчику путём неподтверждения последнего байта. Ведомый-передатчик должен освободить линию данных для того, чтобы позволить ведущему выдать состояние СТОП или повторить состояние СТАРТ.
Синхронизация
Синхронизация выполняется с использованием подключения к линии SCL по правилу монтажного И. Это означает, что ведущий не имеет монопольного права на управление переходом линии SCL из НИЗКОГО состояния в ВЫСОКОЕ. В том случае, когда ведомому необходимо дополнительное время на обработку принятого бита, он имеет возможность удерживать линию SCL в низком состоянии до момента готовности к приёму следующего бита. Таким образом, линия SCL будет находиться в НИЗКОМ состоянии на протяжении самого длинного НИЗКОГО периода синхросигналов.

Устройства с более коротким НИЗКИМ периодом будут входить в состояние ожидания на время, пока не кончится длинный период. Когда у всех задействованных устройств кончится НИЗКИЙ период синхросигнала, линия SCL перейдет в ВЫСОКОЕ состояние. Все устройства начнут проходить ВЫСОКИЙ период своих синхросигналов. Первое устройство, у которого кончится этот период, снова установит линию SCL в НИЗКОЕ состояние. Таким образом, НИЗКИЙ период синхролинии SCL определяется наидлиннейшим периодом синхронизации из всех задействованных устройств, а ВЫСОКИЙ период определяется самым коротким периодом синхронизации устройств.

Механизм синхронизации может быть использован приёмниками как средство управления пересылкой данных на байтовом и битовом уровнях.

На уровне байта, если устройство может принимать байты данных с большой скоростью, но требует определенное время для сохранения принятого байта или подготовки к приёму следующего, то оно может удерживать линию SCL в НИЗКОМ состоянии после приёма и подтверждения байта, переводя таким образом передатчик в состояние ожидания.

На уровне битов устройство, такое, как микроконтроллер без встроенных аппаратных цепей I²C или с ограниченными цепями, может замедлить частоту синхроимпульсов путём продления их НИЗКОГО периода. Таким образом скорость передачи любого ведущего адаптируется к скорости медленного устройства.
Адресация в шине I²C
Каждое устройство, подключённое к шине, может быть программно адресовано по уникальному адресу. Для выбора приёмника сообщения ведущий использует уникальную адресную компоненту в формате посылки. При использовании однотипных устройств ИС часто имеют дополнительный селектор адреса, который может быть реализован как в виде дополнительных цифровых входов селектора адреса, так и в виде аналогового входа.

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

В обычном режиме используется 7-битная адресация.

Процедура адресации на шине I²C заключается в том, что первый байт после сигнала СТАРТ определяет, какой ведомый адресуется ведущим для проведения цикла обмена. Исключение составляет адрес «Общего вызова», который адресует все устройства на шине. Когда используется этот адрес, все устройства в теории должны послать сигнал подтверждения. Однако устройства, которые могут обрабатывать «общий вызов», на практике встречаются редко.

Первые семь битов первого байта образуют адрес ведомого. Восьмой, младший бит, определяет направление пересылки данных. «Ноль» означает, что ведущий будет записывать информацию в выбранного ведомого. «Единица» означает, что ведущий будет считывать информацию из ведомого.

После того, как адрес послан, каждое устройство в системе сравнивает первые семь бит после сигнала СТАРТ со своим адресом. При совпадении устройство полагает себя выбранным как ведомый-приёмник или как ведомый-передатчик, в зависимости от бита направления.

Адрес ведомого может состоять из фиксированной и программируемой части. Часто случается, что в системе будет несколько однотипных устройств (к примеру, ИМС памяти, или драйверов светодиодных индикаторов), поэтому при помощи программируемой части адреса становится возможным подключить к шине максимально возможное количество таких устройств. Количество программируемых бит в адресе зависит от количества свободных выводов микросхемы. Иногда используется один вывод с аналоговой установкой программируемого диапазона адресов. При этом в зависимости от потенциала на этом адресном выводе ИМС, возможно смещение адресного пространства драйвера так, чтобы однотипные ИМС не конфликтовали между собой на общей шине.

Все специализированные ИМС, поддерживающие работу в стандарте шины I²C, имеют набор фиксированных адресов, перечень которых указан производителем в описаниях контроллеров.

Комбинация бит 11110ХХ адреса зарезервирована для 10-битной адресации.

Как следует из спецификации шины, допускаются как простые форматы обмена, так и комбинированные, когда в промежутке от состояния СТАРТ до состояния СТОП ведущий и ведомый могут выступать и как приёмник, и как передатчик данных. Комбинированные форматы могут быть использованы, например, для управления последовательной памятью.

Во время первого байта данных можно передавать адрес в памяти, который записывается во внутренний регистр-защёлку. После повторения сигнала СТАРТа и адреса ведомого выдаются данные из памяти. Все решения об авто-инкременте или декременте адреса, к которому произошёл предыдущий доступ, принимаются конструктором конкретного устройства. Поэтому в любом случае лучший способ избежать неконтролируемой ситуации на шине перед использованием новой (или ранее не используемой) ИМС — следует тщательно изучить её описание (datasheet или reference manual), получив его с сайта производителя. Более того, производители часто размещают рядом более подробные инструкции по применению.

В любом случае по спецификации шины все разрабатываемые устройства должны сбрасывать логику шины при получении сигнала СТАРТ или повторный СТАРТ и подготавливаться к приёму адреса.

Тем не менее, основные проблемы с использованием I²C шины возникают именно из-за того, что разработчики, «начинающие» работать с I²C шиной, не учитывают того факта, что ведущий (часто — микропроцессор) не имеет монопольного права ни на одну из линий шины.

История и Стандарты :

Первый стандарт работал на частоте 100 КГц (Standart ) Скорость - 100 Кбит/с или 12,5 КБ/с
Затем частота увеличилась до 400 КГц (Fast ) Скорость - 400 Кбит/с или 50 КБ/с
Следующий стандарт ввел новые скорости и частоты 1,7 или 3,4 МГц (High ) Скорость - (1,7 Мбит/с или 3,4 Мбит/с) 500 КБ/с или 1000 КБ/с
В случаях когда этих скоростей недостаточно используется более быстрый интерфейс SPI

Особенности:

В покое На шине постоянно положительный потенциал (~3В или 5В но могут быть и другие). А процессор понижая потенциал дает команду на переход к готовности. Для поддержания положительного потенциала возле шины ставяться подтягивающие резистоы (Vdd см. рисунок) на плюсовое питание по обеим линиям. Обчно ставять резисторы на 10 КОм на +3,3 В

Использование:

1. Связь процессора с памятью (чаще EEPROM)
2. HDMI и DVI интерфейсы (для передачи служебной информации от телевизора к устройству которое воспроизводит видеоконтент, либо для передачи информации от монитора к компьютеру для передачи информации, что за монитор подключили с какими характеристикаи, передача информации от термостата ЦП или информация о скорости вращения кулера и т.д.)
3. Микросхемы и карты памяти (EEPROM, RAM, FERAM, Flash);
4. Доступ к низкоскоростным ЦАП/АЦП;
5. Регулировка контрастности, насыщенности и цветового баланса мониторов;
6. Регулировка звука в динамиках;
7. Управление светодиодами, в том числе в мобильных телефонах;
8. Чтение информации с часов реального времени (кварцевых генераторов);
9. Управление включением/выключением питания системных компонент;
10. Клавиатуры
11. Информационный обмен между микроконтроллерами;

Пример системы с шиной I²C:
На рисунке (Кликабельно):
(a) Высокоинтегрированный телевизор
Микроконтроллер
ФАПЧ-синтезатор
Флеш-память
Мультисистемный декодер сигналов цветности
Стереодекодер звука
Улучшитель сигнала картинки
Hi-Fi аудиопроцессор
Аналоговый видеопроцессор
Декодер телетекста
ИМС сигналов OSD
(b) базовая станция радиотелефона стандарта DECT
Генератор DTMF
Интерфейс телефонной линии
Кодек АДИКМ
Пакетный контроллер
Микроконтроллер

Частые проблемы на шине и их диагностика:

- Первое что надо проверить после БП и тактирования на кварце - Чатсто происходит обрыв подтягивающих резисторов. Диагностируется измерением потенциала на линиях SCL и SDA. Если шина просажена тоесть один из резисторов не додает положительное напряжение, то аппарат может не запускаться...

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

Этот недостаток отсутствует у интерфейса I 2 C (Inter-Integrated Circuit) . Он был первоначально разработан фирмой Philips в конце 1970-х годов специально для того, чтобы обеспечивать такой способ подключения периферийных устройств к микропроцессорам, который не требовал бы использования традиционных шин адреса, данных и управления, а кроме того, позволял бы нескольким микропроцессорам работать с одними и теми же периферийными устройствами (multimastering ). Philips запатентовал название интерфейса и до 2007 у различных производителей этот микроконтроллер имел свое название. Например, в микроконтроллерах ATmega, на которых строится Arduino, этот интерфейс носит название 2-wire Serial Interface (двухпроводной последовательный интерфейс).

Использует асинхронный протокол передачи данных, потому что приемник не получает какого-либо сигнала тактирования в явном виде. На рисунке ниже показаны временные диаграммы сигналов при синхронной передаче данных. Здесь приемник фиксирует данные на линии Data по переднему или заднему фронту синхроимпульсов Clock .

Интерфейс I 2 C использует всего две линии — они именуются SCL (Serial Clock ) и SDA (Serial Data ). Первая предназначена для передачи синхроимпульсов (они формируются тем устройством, которое в настоящий момент передает данные), а вторая — для передачи самих данных и команд, управляющих этим процессом. Обе линии имеют открытый коллектор (как и во многих других случаях, когда необходимо, чтобы к одной линии мого подключаться несколько различных устройств), поэтому требуют подключения «подтягивающих» резисторов сопротивлением 1-10 кОм.

Для примера на рисунке ниже показана структурная схема устройства управления стереосистемой.

Устройство управления стереосистемой на основе интерфейса I 2 C

В обмене информацией по шине I 2 C всегда принимают участие два устройства — ведущее (master , задатчик) и ведомое . Ведущее устройство вырабатывает синхроимпульсы, а принимать или передавать данные может как задатчик, так и ведомое устройство.

Пока ни одно устройство не начало передачу данных, благодаря подтягивающим резисторам на обоих линиях шины I 2 C действует напряжение высокого уровня. Если какое-либо устройство собирается начать передачу данных, оно сначала проверяет, свободна ли шина. Ведь в каждый момент времени ведущим на шине может быть только одно устройство. Напряжение высокого уровня на линии SCL показывает, что шина пока свободна.

Перед началом процесса передачи задатчик устанавливает напряжение низкого уровня сначала на линии SDA , а затем на линии SCL (см. рисунок ниже). В процессе передачи данных такое состояние линий невозможно, поскольку сигнал на линии SDA не должен изменяться во время действия тактового импульса на линии SCL .

Начало и конец передачи данных по интерфейсу I 2 C

Затем начинается передача данных от ведущего устройства к ведомому (slave ) или наоборот, но в любом случае источником синхроимпульсов является задатчик. Данные фиксируются приемником по заднему фронту синхроимпульсов.

В конце передачи ведущее устройство прекращает генерацию синхроимпульсов; в результате на линии SCL благодаря подтягивающему резистору устанавливается напряжение высокого уровня, после этого отключается передатчик, из-за чего устанавливается высокий уровень на линии SDA — иными словами, повторяется ситуация, обратная той, что наблюдалась перед началом передачи.

В отличие от интерфейса RS-232 , передача данных производится начиная со старшего бита; при этом используются обычные логические уровни микросхем ТТЛ/КМОП. После передачи последнего (восьмого) бита каждого байта во время действия очередного синхроимпульса передатчик отключается от линии SDA , чтобы дать возможность приемнику подтвердить получение данных. Для этого приемник должен выставить на линии SDA сигнал низкого уровня. Перед посылкой очередного бита сигнал низкого уровня действует на обеих линиях. Временные диаграммы на рисунке ниже иллюстрируют процесс передачи одного байта данных по интерфейсу I 2 C .

Передача данных по интерфейсу I 2 C

В некоторых случаях бит подтверждения передается высоким уровнем сигнала, даже если прием прошел успешно. Это показывает, что обмен закончен и передатчик (обычно являющийся либо ведущим устройством, либо задатчиком, который не должен сам начинать операцию обмена) может подготовиться к получению следующего запроса. Этот режим используется, когда микроконтроллер запрашивает данные у какого-либо периферийного устройства. В этом случае является приемником данных. Если вместо бита подтверждения микроконтроллер выставит сигнал высокого уровня, то ведомое устройство «поймет», что следующую порцию данных пересылать не нужно.

Минимальная скорость передачи по интерфейсу I 2 C ничем не ограничена. И передатчик, и приемник могут при необходимости замедлять процесс обмена на неопределенное время. Задатчик делает это, удерживая сигнал высокого уровня на линии SCL после приема или передачи предыдущего бита. Ведомое устройство может замедлить работу задатчика, удерживая сигнал на линии SCL на низком уровне после приема или передачи очередного бита (увидев это, задатчик не сможет выставить на линии SCL следующий синхроимпульс).

Cуществуют три максимальные скорости передачи. В так называемом стандартном режиме это 100 Кбит/с (частота синхроимпульсов 100 кГц), в быстром режиме — 400 Кбит/с (частота синхроимпульсов 400 кГц), в высокоскоростном режиме - 3.4 Мбит/с и в ультравысокоскоростном режиме — до 5 Мбит/с. Правда, устройств, работающих на мегабитных скоростях еще нужно поискать. Помимо скоростных ограничений, есть и ограничения на максимальное количество подключенных к шине I 2 C устройств. В стандартном режиме можно адресовать 127 устройств (7-битный адрес), в быстром режиме до 1023 устройств (10-битный адрес). На рисунке ниже показаны минимальные временные задержки для обоих режимов (все значения указаны в микросекундах).

Минимальные временные задержки для двух режимов передачи данных по интерфейсу I 2 C

На рисунке ниже показан формат команд, используемых для управления процессом передачи данных по интерфейсу I 2 C .

Формат управляющих команд интерфейcа I 2 C

Адрес получателя задается семью битами. Старшие четыре бита адреса определяют тип устройства, а оставшиеся три младших бита указывают, какому именно устройству (из восьми возможных) этого типа предназначена посылаемая информация.

В некоторых случаях требуется чуть усложнять протокол обмена. Например, при чтении информации из памяти EEPROM (или записи данных в память) задатчик должен сначала установить стартовую последовательность, чтобы переслать адрес нужной ячейки памяти, а затем снова выполнить стартовую последовательность, чтобы теперь уже считать данные из памяти (или записать их).

Для того, чтобы ведущими на шине могли быть различные устройства, необходим какой-либо протокол разрешения коллизий (конфликтов). Коллизия возникает, когда два устройства, одновременно проверив состояние шины и, обнаружив, что она пока свободна, начинают передачу данных.

Конфликты разрешаются благодаря тому, что на линии с открытым коллектором подача сигнала высокого уровня реализуется, на самом деле, простым отключением активного устройства (вспомните о «подтягивающих» резисторах). В этом случае, побеждает всегда то устройство, которое выставило сигнал низкого уровня. Тогда втрое устройство, «увидев», что действующий на линии уровень напряжения не совпадает с тем, который оно пытается установить, «понимает», что на шине активен еще один задатчик, и на время отключается, чтобы дать ему возможность беспрепятственно закончить обмен информацией.

Реализация интерфейса I 2 C с помощью микроконтроллеров весьма проста. Однако, из-за программной его реализации трудно достичь высоких скоростей передачи. Даже максимальная скорость стандартного режима (100 Кбит/с) может оказаться недостижимой.

Программная реализация интерфейса I 2 C все же является наилучшим решением, если кроме микроконтроллера на шине не может быть других задатчиков. Ведь в этом случае, не требуется синхронизировать его работу с какими-либо быстрыми устройствами, в которых используется аппаратная реализация этого интерфейса.

Полную спецификацию и руководство пользователя для шины I2C можно скачать по ссылке:

Category: Documents
Date: 04.03.2015

Преимущества интерфейса I 2 C

  • необходим всего один микроконтроллер для управления набором устройств;
  • используется всего два проводника для подключения многих устройств;
  • возможна одновременная работа нескольких ведущих (master ) устройств, подключенных к одной шине I 2 C ;
  • стандарт предусматривает «горячее» подключение и отключение устройств в процессе работы системы;
  • встроенный в микросхемы, реализующие интерфейс фильтр подавляет всплески, обеспечивая целостность данных.

Недостатки интерфейса I 2 C

  • ограничение на ёмкость линии - 400 пФ;
  • несмотря на простоту протокола, программирование контроллера I 2 C затруднено из-за изобилия возможных нештатных ситуаций на шине. По этой причине большинство систем используют I²C c единственным ведущим (master ) устройством и распространённые драйверы поддерживают только монопольный режим обмена по I 2 C;
  • Трудность локализации неисправности, если одно из подключенных устройств ошибочно устанавливает на шине состояние низкого уровня.

Интерфейс I2C является широко распространенным и популярным стандартом передачи данных между устройствами. Данный интерфейс поддерживают множество различных датчиков и микросхем, наиболее известные это микросхемы EEPROM памяти серии 24cXX. Для передачи данных используются всего две линии, которые представляют собой шину данных, причем на одну шину можно подключать несколько различных устройств. В этой статье я приведу описание интерфейса и реализацию на программном уровне.

Описание интерфейса I2C

Способ подключения

В интерфейсе используются два провода, это линия тактирования SCL, и линия передачи данных SDA, которые вместе образуют шину данных. Устройства, подключенные к шине подразделяются на ведущего и ведомого. Ведущий инициализирует процесс передачи данных и выдает тактовые импульсы на линию SCL, ведомый принимает команды /данные, а также выдает данные по запросу ведущего. Линии SDA и SCL двунаправленные, устройства подключаемые к шине должны иметь выводы перенастраиваемые на вход и выход. Причем тип выхода должен быть с открытым коллектором или открытым стоком, в связи с чем, обе линии SDA и SCL через резисторы подтягиваются к положительному полюсу источника питания. На следующей картинке приведена схема подключения интерфейса I2C:


В случае использования микроконтроллера, для установки лог. 1 на линии, достаточно перенастроить порт микроконтроллера на вход, при этом резистор “подтянет” линию к высокому логическому уровню, подача высокого логического уровня с порта микроконтроллера на линию не допускается. Для установки лог. 0 на линии, порт перенастраивается на выход, в выходную защелку заранее записывается значение 0, при этом линия “прижимается” к низкому логическому уровню.

Адресация

В интерфейсе предусмотрена программная адресация устройств подключенных к шине, наиболее распространена длина адреса в 7 бит, теоретически это позволяет подключать на шину до 127 устройств, но часть адресов по спецификации зарезервированы и не могут использоваться разработчиками. Каждое устройство имеет свой уникальный адрес, который заложен производителем и указан в технической документации. Адрес устройства может быть фиксированным, или с возможностью аппаратной настройки, в этом случае устройство имеет дополнительные входы, в зависимости от уровня напряжения на входах (высокое или низкое), можно получить различные адреса. Обычно количество входов варьируется от 1-го до 3-х, которые задают значения определенных битов 7-битного адреса. Аппаратная настройка адреса предусмотрена для возможности подключения нескольких однотипных устройств на одну шину.

Также интерфейс предусматривает более редкую 10-битную адресацию, под которую зарезервирован 7-битный адрес 11110XX (XX-зависят от значения адреса), в этом случае сначала предается зарезервированный адрес, в котором два последних бита представляют собой старшие биты 10-битного адреса, затем передаются младшие 8 бит адреса. При использовании данной адресации на шину можно подключать более 1000 устройств.

Условия “Старт” и “Стоп”

Каждый сеанс передачи данных начинается со специального условия, называемого “Старт”. В исходном состоянии, когда шина свободна, обе линии SDA и SCL подтянуты к высокому логическому уровню, условие “Старт” подразумевает переключение линии SDA с высокого логического уровня на низкий, в то время когда на линии SCL установлен высокий уровень.

Аналогично, сеанс передачи данных завершается специальным условием “Стоп”, это переключение линии SDA с низкого логического уровня на высокий, при высоком уровне на линии SCL. Данные условия генерирует ведущий (микроконтроллер).

Исходя из условий “Старт” и “Стоп”, во время передачи данных линия SDA может переключаться только при низком уровне на линии SCL, то есть установка новых данных на линии SDA возможна только после спада уровня на SCL. В течение импульса тактирования (высокий уровень на SCL), состояние линии SDA не должно меняться, в это время выполняется считывание данных на SDA.

Формат передачи данных

Данные по интерфейсу передаются побайтно, старшим битом вперед, за каждым переданным байтом (8 бит) следует бит подтверждения, устройство (ведущий или ведомый) принявшее байт данных, устанавливает низкий уровень на линии SDA на следующем тактовом импульсе SCL, тем самым подтверждая получение байта. В это время передающее устройство должно опрашивать линию SDA, ожидая ответ об успешном получении байта. Ниже на картинке представлена диаграмма передачи данных по шине I2C:


Сначала передается байт с 7-битным адресом ведомого, значение 8-го бита (R/W) определяет направление передачи данных, нулевое значение соответствует записи данных, то есть передача от ведущего к ведомому. Если бит направления равен 1, то выполняется чтение данных из ведомого.

Ведомый сравнивает переданный адрес со своим и при совпадении откликается, устанавливая низкий уровень на линии SDA (бит подтверждения). Ведущий, получив подтверждение, начинает передавать байты с данными, или принимает их, в зависимости от направления передачи. На следующей картинке более подробно представлены различные варианты передачи данных по шине I2C:


После передачи адреса ведомого, передается адрес регистра, над которым будут производиться операции чтения/записи. Каждое устройство обладает своим набором внутренних регистров, назначение которых указано в технической документации.

Запись одного байта состоит из следующей последовательности: условие “Старт” – адрес ведомого (бит R/W сброшен) – адрес внутреннего регистра ведомого – данные (1 байт) – условие “Стоп”. Запись нескольких байтов практически ничем не отличается, после отправки первого байта данных, передаются остальные байты, сеанс заканчивается условием “Стоп”. При этом данные записываются в регистры последовательно, начиная с заданного адреса, обычно ведомый выполняет автоматический инкремент адреса внутренних регистров.

Для чтения одного байта данных, необходимо сначала передать адрес ведомого и адрес требуемого регистра, при этом бит направления должен быть сброшен на запись, после чего повторно передается условие “Старт”, затем снова адрес ведомого, в этот раз с установленным битом направления на чтение. Далее выполняется прием байта данных от ведомого, для окончания сеанса передачи ведущий не выдает подтверждения, то есть на линии SDA остается высокий уровень на время бита подтверждения, далее следует условие “Стоп”. Чтение нескольких байтов выглядит аналогично, ведущий выдает подтверждение после каждого принятого байта, за исключением последнего байта. Как и в случае записи, ведомый выполняет автоматический инкремент адреса, начиная с заданного.

Во время сеанса передачи данных ведомый может принудительно удерживать на линии SCL низкий уровень, например, если ему требуется время на обработку данных. Ведущий “отпуская” линию SCL должен проверить переход от низкого логического уровня к высокому, если этого не произошло, то необходимо ожидать перехода. Таким образом, ведущий не имеет абсолютного права на управление линией SCL.

Интерфейс также предусматривает режим конкуренции, когда на шине присутствуют несколько ведущих, я не стану рассматривать этот режим, так как он редко применяется. Для предотвращения конфликтов в таких случаях используется функция арбитража и синхронизации линии тактирования SCL.

Скорость передачи данных

По спецификации интерфейс поддерживает три скоростных режима передачи:

  1. Самый распространенный до 100 Кбит/сек, частота тактирования линии SCL до 100 кГц, длительность высокого и низкого уровней не менее 5 мкс.
  2. Скоростной режим до 400 Кбит/сек, частота тактирования до 400 кГц.
  3. Высокоскоростной режим до 3,4 Мбит/сек, частота тактирования до 3,4 МГц.

Стандартный режим до 100 Кбит/сек поддерживают все устройства, возможность функционирования на больших скоростях необходимо уточнять в технической документации на устройство.

Программная реализация интерфейса I2C

Не у всех микроконтроллеров серии PIC16 имеется встроенный аппаратный модуль I2C, но интерфейс можно реализовать программно и использовать на любом микроконтроллере. Ниже представлен код реализующий функции ведущего применительно к микроконтроллеру PIC16F628A:

#include LIST p=16F628A __CONFIG H"3F10" ;Конфигурация микроконтроллера errorlevel -302 ;не выводить сообщения с ошибкой 302 в листинге scetbit equ 0020h ;вспомогательный регистр счета кол-ва бит perem equ 0021h ;вспомогательный регистр приема/передачи байта adr_i2c equ 0022h ;регистр хранения адреса внутреннего регистра ведомого tmp_i2c equ 0023h ;регистр кол-ва передаваемых байт slave_adr equ 0024h ;регистр хранения адреса ведомого data_i2c equ 0025h ;начальный регистр хранения данных для передачи flag equ 007Fh ;регистр флагов #DEFINE sda PORTB,0 ;линия sda #DEFINE scl PORTB,1 ;линия scl #DEFINE sda_io TRISB,0 ;бит управления направлением линии sda #DEFINE scl_io TRISB,1 ;бит управления направлением линии scl ;flag,4 - флаг направления передачи (0 - чтение, 1 - запись) ;flag,5 - флаг окончания приема данных от ведомого;flag,6 - флаг ошибки передачи по интерфейсу I2C (отсутствие подтверждения от ведомого) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; org 0000h ;начать выполнение программы с адреса 0000h goto Start ;переход на метку Start ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Основная программа Start movlw b"00000000" ;установка значений выходных защелок порта B movwf PORTB ; movlw b"00000111" ;выключение компараторов movwf CMCON ; bsf STATUS,RP0 ;выбрать 1-й банк movlw b"11111111" ;настройка линий ввода\вывода порта B movwf TRISB ;все линии на вход bcf STATUS,RP0 ;выбрать 0-й банк;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; movlw b"01111110" ;запись адреса ведомого (0111111) в регистр slave_adr movwf slave_adr ; ;пример записи 2-х байт данных (числа 10 и 20) во внутренние регистры;устройства (ведомого) начиная с адреса 0x03, адрес ведомого 0111111 movlw 0x03 ;запись адреса внутреннего регистра ведомого в регистр adr_i2c movwf adr_i2c ;(для примера адрес внутреннего регистра ведомого равен 0x03) movlw .2 ;запись кол-ва передаваемых байт в регистр tmp_i2c movwf tmp_i2c ;(для примера передается 2 байта) movlw data_i2c ;установка начального регистра хранения данных для передачи movlw .10 ;запись числа 10 в первый регистр хранения movwf INDF ; , подготовка следующего регистра хранения movlw .20 ;запись числа 20 во второй регистр хранения movwf INDF ; call write_i2c ;вызов подпрограммы записи по интерфейсу I2C goto dalee_1 ;нет ошибки, переход на метку dalee_1 ................... ................... ;пример чтения 3-х байт данных из внутренних регистров устройства (ведомого) ;начиная с адреса 0x05, адрес ведомого был задан ранее 0111111 movlw 0x05 ;запись адреса внутреннего регистра ведомого в регистр adr_i2c movwf adr_i2c ;(для примера адрес внутреннего регистра ведомого равен 0x05) movlw .3 ;запись кол-ва принимаемых байт в регистр tmp_i2c movwf tmp_i2c ;(для примера принимается 3 байта) call read_i2c ;вызов подпрограммы чтения по интерфейсу I2C btfss flag,6 ;проверка ошибки передачи данных goto obrabotka ;нет ошибки, переход на метку obrabotka ................... ;обработка ошибки................... ; ................... ; obrabotka movlw data_i2c ;установка начального регистра хранения принятых данных movwf FSR ;с помощью косвенной аддресации movf INDF,W ;копирование первого принятого байта в аккумулятор................... ;обработка первого байта................... ; incf FSR,F ;инкремент регистра FSR movf INDF,W ;копирование второго принятого байта в аккумулятор................... ;обработка второго байта................... ; incf FSR,F ;инкремент регистра FSR movf INDF,W ;копирование третьего принятого байта в аккумулятор................... ;обработка третьего байта................... ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;подпрограмма чтения/записи по интерфейсу I2C write_i2c bsf flag,4 ;установка флага направления передачи (для записи) goto i2c_1 ;переход на метку i2c_1 read_i2c bcf flag,4 ;сброс флага направления передачи (для чтения) bcf flag,5 ;сброс флага окончания приема данных i2c_1 bcf flag,6 ;сброс флага ошибки I2C call starti2c ;вызов подпрограммы "Старт" bcf slave_adr,0 ;сброс бита R/W для операции записи goto err_i2c ;ошибка:переход на метку err_i2c movf adr_i2c,W ;адреса регистра ведомого I2C call peredi2c ;вызов подпрограммы передача байта btfsc flag,6 ;проверка флага ошибки movlw .0 ;проверка кол-ва передаваемых байт xorwf tmp_i2c,W ; btfss STATUS,Z ; goto i2c_3 ;кол-во передаваемых байт не равно 0: переход на метку i2c_3 call stopi2c ;кол-во передаваемых байт равно 0: вызов подпрограммы "Стоп" i2c_3 movlw data_i2c ;установка начального регистра хранения данных для передачи movwf FSR ;с помощью косвенной аддресации decf FSR,F ; btfss flag,4 ;проверка флага направления передачи goto rd_i2c ;флаг равен 0: переход на метку rd_i2c (чтение) i2c_2 incf FSR,F ;инкремент регистра FSR, подготовка следующего байта для передачи movf INDF,W ;копирование байта данных для передачи call peredi2c ;вызов подпрограммы передача байта btfsc flag,6 ;проверка флага ошибки goto err_i2c ;ошибка: переход на метку err_i2c decfsz tmp_i2c,F ;декремент счетчика кол-ва передаваемых байт goto i2c_2 ;счетчик не равен 0: переход на метку i2c_2 return ;выход из подпрограммы чтения/записи I2C ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; rd_i2c call starti2c ;вызов подпрограммы "Старт" (Повторный Старт) bsf slave_adr,0 ;установка бита R/W для операции чтения movf slave_adr,W ;копирование адреса ведомого call peredi2c ;вызов подпрограммы передача байта btfsc flag,6 ;проверка флага ошибки goto err_i2c ;ошибка: переход на метку err_i2c rd_i2c_2 decfsz tmp_i2c,F ;декремент счетчика кол-ва передаваемых байт goto rd_i2c_1 ;счетчик не равен 0: переход на метку rd_i2c_1 bsf flag,5 ;установка флага окончания приема данных от ведомого rd_i2c_1 incf FSR,F ;инкремент регистра FSR, подготовка следующего регистра для приема данных call priemi2c ;вызов подпрограммы приема байта movwf INDF ;сохранение принятого байта в регистр INDF btfss flag,5 ;проверка флага окончания приема данных от ведомого goto rd_i2c_2 ;флаг не равен 0: переход на метку rd_i2c_2 call stopi2c ;вызов подпрограммы "Стоп" return ;выход из подпрограммы чтения/записи I2C err_i2c call stopi2c ;вызов подпрограммы "Стоп" return ;выход из подпрограммы чтения/записи I2C ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; starti2c call scl_1 ;отпустить линию scl call sda_0 ;притянуть к 0 линию sda call pausi2c ;вызов подпрограммы паузы call scl_0 ;притянуть к 0 линию scl call pausi2c ;вызов подпрограммы паузы stopi2c call sda_0 ;притянуть к 0 линию sda call pausi2c ;вызов подпрограммы паузы call scl_1 ;отпустить линию scl stpi2c_1 call pausi2c ;вызов подпрограммы паузы btfss scl ;проверка линии SCL на занятость ведомого goto stpi2c_1 ;ведомый занят: переход на метку stpi2c_1 call sda_1 ;отпустить линию sda call pausi2c ;вызов подпрограммы паузы return ;возврат из подпрограммы sda_1 bsf STATUS,RP0 ;перенастройка линии sda на вход bsf sda_io ; bcf STATUS,RP0 ; return ;возврат из подпрограммы sda_0 bcf sda ;перенастройка линии sda на выход bsf STATUS,RP0 ; bcf sda_io ; bcf STATUS,RP0 ; return ;возврат из подпрограммы scl_1 bsf STATUS,RP0 ;перенастройка линии scl на вход bsf scl_io ; bcf STATUS,RP0 ; return ;возврат из подпрограммы scl_0 bcf scl ;перенастройка линии scl на выход bsf STATUS,RP0 ; bcf scl_io ; bcf STATUS,RP0 ; return ;возврат из подпрограммы;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Подпрограмма передачи байта по интерфейсу i2c peredi2c movwf perem ;сохранение передаваемых данных в регистр perem movlw .8 ;запись счетчика бит movwf scetbit ; prd_i2c_1 btfsc perem,7 ;опрос старшего бита передаваемого байта call sda_1 ;отпустить линию sda btfss perem,7 ;опрос старшего бита передаваемого байта call sda_0 ;притянуть к 0 линию sda call scl_1 ;отпустить линию scl prd_i2c_2 call pausi2c ;вызов подпрограммы паузы btfss scl ;проверка линии SCL на занятость ведомого goto prd_i2c_2 ;ведомый занят: переход на метку prd_i2c_2 call scl_0 ;притянуть к 0 линию scl call pausi2c ;вызов подпрограммы паузы rlf perem,F ;смещение содержимого регистра perem, подготовка бита для передачи decfsz scetbit,F ;декремент счетчика бит goto prd_i2c_1 ;счетчик не равен 0: переход на метку prd_i2c_1 call sda_1 ;отпустить линию sda call scl_1 ;отпустить линию scl prd_i2c_3 call pausi2c ;вызов подпрограммы паузы btfss scl ;проверка линии SCL на занятость ведомого goto prd_i2c_3 ;ведомый занят: переход на метку prd_i2c_3 movlw .20 ;запись счетчика времени (100 мкс) для приема подтверждения movwf scetbit ; prd_i2c_4 btfss sda ;опрос линии sda goto prd_i2c_5 ;низкий уровень на sda, подтверждение получено: переход на prd_i2c_5 decfsz scetbit,F ;высокий уровень на sda, декремент счетчика времени goto prd_i2c_4 ;счетчик не равен 0: переход на метку prd_i2c_4 bsf flag,6 ;счетчик равен 0, нет потверждения, устанавливаем флаг ошибки prd_i2c_5 call scl_0 ;притянуть к 0 линию scl call pausi2c ;вызов подпрограммы паузы return ;возврат из подпрограммы передачи байта;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;подпрограмма приема байта по интерфейсу i2c priemi2c movlw .8 ;запись счетчика бит movwf scetbit ; call sda_1 ;отпустить линию sda prm_i2c_1 rlf perem,F ;смещение содержимого регистра perem, подготовка для приема бита call scl_1 ;отпустить линию scl prm_i2c_2 call pausi2c ;вызов подпрограммы паузы btfss scl ;проверка линии SCL на занятость ведомого goto prm_i2c_2 ;ведомый занят: переход на метку prm_i2c_2 btfsc sda ;опрос линии sda bsf perem,0 ;установка 0-го бита регистра perem, принят бит=1 btfss sda ;опрос линии sda bcf perem,0 ;сброс 0-го бита регистра perem, принят бит=0 call scl_0 ;притянуть к 0 линию scl call pausi2c ;вызов подпрограммы паузы decfsz scetbit,F ;декремент счетчика бит goto prm_i2c_1 ;счетчик не равен 0: переход на метку prm_i2c_1 btfss flag,5 ;проверка флага окончания приема данных от ведомого call sda_0 ;флаг равен 0, прием не окончен, притянуть к 0 линию sda (подтверждение) call scl_1 ;отпустить линию scl prm_i2c_3 call pausi2c ;вызов подпрограммы паузы btfss scl ;проверка линии SCL на занятость ведомого goto prm_i2c_3 ;ведомый занят: переход на метку prm_i2c_3 call scl_0 ;притянуть к 0 линию scl call pausi2c ;вызов подпрограммы паузы movf perem,W ;копирование принятого байта от ведомого return ;возврат из подпрограммы;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Подпрограмма паузы 5 машинных тактов pausi2c nop ;пустая команда return ;возврат из подпрограммы паузы;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

#include

CONFIG H"3F10" ;Конфигурация микроконтроллера

errorlevel -302 ;не выводить сообщения с ошибкой 302 в листинге

scetbit equ 0020h ;вспомогательный регистр счета кол-ва бит

perem equ 0021h ;вспомогательный регистр приема/передачи байта

adr_i2c equ 0022h ;регистр хранения адреса внутреннего регистра ведомого

tmp_i2c equ 0023h ;регистр кол-ва передаваемых байт

slave_adr equ 0024h ;регистр хранения адреса ведомого

data_i2c equ 0025h ;начальный регистр хранения данных для передачи

flag equ 007Fh ;регистр флагов

#DEFINE sda PORTB,0 ;линия sda

#DEFINE scl PORTB,1 ;линия scl

#DEFINE sda_io TRISB,0 ;бит управления направлением линии sda

#DEFINE scl_io TRISB,1 ;бит управления направлением линии scl

;flag,4 - флаг направления передачи (0 - чтение, 1 - запись)

;flag,5 - флаг окончания приема данных от ведомого

;flag,6 - флаг ошибки передачи по интерфейсу I2C (отсутствие подтверждения от ведомого)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

org 0000h ;начать выполнение программы с адреса 0000h

goto Start ;переход на метку Start

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;Основная программа

Start movlw b"00000000" ;установка значений выходных защелок порта B

movlw b"00000111" ;выключение компараторов

bsf STATUS,RP0 ;выбрать 1-й банк

movlw b"11111111" ;настройка линий ввода\вывода порта B

movwf TRISB ;все линии на вход

bcf STATUS,RP0 ;выбрать 0-й банк

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

movlw b"01111110" ;запись адреса ведомого (0111111) в регистр slave_adr

movwf slave_adr ;

;пример записи 2-х байт данных (числа 10 и 20) во внутренние регистры

;устройства (ведомого) начиная с адреса 0x03, адрес ведомого 0111111

movlw 0x03 ;запись адреса внутреннего регистра ведомого в регистр adr_i2c

movwf adr_i2c ;(для примера адрес внутреннего регистра ведомого равен 0x03)

movlw .2 ;запись кол-ва передаваемых байт в регистр tmp_i2c

movwf tmp_i2c ;(для примера передается 2 байта)

movlw data_i2c ;установка начального регистра хранения данных для передачи

movwf FSR ;с помощью косвенной аддресации

movlw .10 ;запись числа 10 в первый регистр хранения

incf FSR,F ;инкремент регистра FSR, подготовка следующего регистра хранения

movlw .20 ;запись числа 20 во второй регистр хранения

call write_i2c ;вызов подпрограммы записи по интерфейсу I2C

btfss flag,6 ;проверка ошибки передачи данных

goto dalee_1 ;нет ошибки, переход на метку dalee_1

................... ;обработка ошибки

...................

...................

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;пример чтения 3-х байт данных из внутренних регистров устройства (ведомого)

;начиная с адреса 0x05, адрес ведомого был задан ранее 0111111

movlw 0x05 ;запись адреса внутреннего регистра ведомого в регистр adr_i2c

movwf adr_i2c ;(для примера адрес внутреннего регистра ведомого равен 0x05)

movlw .3 ;запись кол-ва принимаемых байт в регистр tmp_i2c

movwf tmp_i2c ;(для примера принимается 3 байта)

call read_i2c ;вызов подпрограммы чтения по интерфейсу I2C

btfss flag,6 ;проверка ошибки передачи данных

goto obrabotka ;нет ошибки, переход на метку obrabotka

................... ;обработка ошибки

................... ;

................... ;

obrabotka movlw data_i2c ;установка начального регистра хранения принятых данных

movwf FSR ;с помощью косвенной аддресации

movf INDF,W ;копирование первого принятого байта в аккумулятор

................... ;обработка первого байта

................... ;

incf FSR,F ;инкремент регистра FSR

movf INDF,W ;копирование второго принятого байта в аккумулятор

................... ;обработка второго байта

................... ;

incf FSR,F ;инкремент регистра FSR

movf INDF,W ;копирование третьего принятого байта в аккумулятор

................... ;обработка третьего байта

................... ;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;подпрограмма чтения/записи по интерфейсу I2C

write_i2c bsf flag,4 ;установка флага направления передачи (для записи)

goto i2c_1 ;переход на метку i2c_1

read_i2c bcf flag,4 ;сброс флага направления передачи (для чтения)

bcf flag,5 ;сброс флага окончания приема данных

i2c_1 bcf flag,6 ;сброс флага ошибки I2C

call starti2c ;вызов подпрограммы "Старт"

bcf slave_adr,0 ;сброс бита R/W для операции записи

movf slave_adr,W ;копирование адреса ведомого

call peredi2c ;вызов подпрограммы передача байта

btfsc flag,6 ;проверка флага ошибки

goto err_i2c ;ошибка:переход на метку err_i2c

movf adr_i2c,W ;адреса регистра ведомого I2C

call peredi2c ;вызов подпрограммы передача байта

btfsc flag,6 ;проверка флага ошибки

goto err_i2c ;ошибка: переход на метку err_i2c

movlw .0 ;проверка кол-ва передаваемых байт

xorwf tmp_i2c,W ;

btfss STATUS,Z ;

goto i2c_3 ;кол-во передаваемых байт не равно 0: переход на метку i2c_3

call stopi2c ;кол-во передаваемых байт равно 0: вызов подпрограммы "Стоп"

return ;выход из подпрограммы чтения/записи I2C

i2c_3 movlw data_i2c ;установка начального регистра хранения данных для передачи

movwf FSR ;с помощью косвенной аддресации

btfss flag,4 ;проверка флага направления передачи

goto rd_i2c ;флаг равен 0: переход на метку rd_i2c (чтение)

i2c_2 incf FSR,F ;инкремент регистра FSR, подготовка следующего байта для передачи

movf INDF,W ;копирование байта данных для передачи

call peredi2c ;вызов подпрограммы передача байта

btfsc flag,6 ;проверка флага ошибки

goto err_i2c ;ошибка: переход на метку err_i2c

goto i2c_2 ;счетчик не равен 0: переход на метку i2c_2

call stopi2c ;вызов подпрограммы "Стоп"

return ;выход из подпрограммы чтения/записи I2C

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

rd_i2c call starti2c ;вызов подпрограммы "Старт" (Повторный Старт)

bsf slave_adr,0 ;установка бита R/W для операции чтения

movf slave_adr,W ;копирование адреса ведомого

call peredi2c ;вызов подпрограммы передача байта

btfsc flag,6 ;проверка флага ошибки

goto err_i2c ;ошибка: переход на метку err_i2c

goto rd_i2c_1 ;счетчик не равен 0: переход на метку rd_i2c_1

bsf flag,5 ;установка флага окончания приема данных от ведомого

rd_i2c_1 incf FSR,F ;инкремент регистра FSR, подготовка следующего регистра для приема данных

call priemi2c ;вызов подпрограммы приема байта

movwf INDF ;сохранение принятого байта в регистр INDF

btfss flag,5 ;проверка флага окончания приема данных от ведомого

goto rd_i2c_2 ;флаг не равен 0: переход на метку rd_i2c_2

call stopi2c ;вызов подпрограммы "Стоп"

return ;выход из подпрограммы чтения/записи I2C

err_i2c call stopi2c ;вызов подпрограммы "Стоп"

return ;выход из подпрограммы чтения/записи I2C

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

starti2c call scl_1 ;отпустить линию scl

call pausi2c ;вызов подпрограммы паузы

call sda_0 ;притянуть к 0 линию sda

call pausi2c ;вызов подпрограммы паузы

call scl_0 ;притянуть к 0 линию scl

call pausi2c ;вызов подпрограммы паузы

return ;возврат из подпрограммы

stopi2c call sda_0 ;притянуть к 0 линию sda

call pausi2c ;вызов подпрограммы паузы

call scl_1 ;отпустить линию scl

stpi2c_1 call pausi2c ;вызов подпрограммы паузы

btfss scl ;проверка линии SCL на занятость ведомого

goto stpi2c_1 ;ведомый занят: переход на метку stpi2c_1

call sda_1 ;отпустить линию sda

call pausi2c ;вызов подпрограммы паузы

return ;возврат из подпрограммы

sda_1 bsf STATUS,RP0 ;перенастройка линии sda на вход

bcf STATUS,RP0 ;

return ;возврат из подпрограммы

sda_0 bcf sda ;перенастройка линии sda на выход

bsf STATUS,RP0 ;

bcf STATUS,RP0 ;

return ;возврат из подпрограммы

scl_1 bsf STATUS,RP0 ;перенастройка линии scl на вход