Использование интерфейса I2C в микроконтроллере PIC16F877


Микроконтроллеры PIC благодаря своей универсальности и относительно невысокой цене находят широкое применение в различных электронных проектах. Но как бы не был универсален микроконтроллер, в больших системах он все равно не может выполнять все операции в одиночку – ему приходится обмениваться данными с другими устройствами с помощью какого-нибудь коммуникационного протокола. К наиболее популярным подобным протоколам (интерфейсам), находящих широкое применение в современной встраиваемой электронике, относятся протоколы USART, IIC (I2C), SPI и CAN. Использование последовательного протокола связи USART в микроконтроллерах PIC мы уже рассматривали на нашем сайте в этой статье, а в данной статье мы рассмотрим использование протокола I2C в микроконтроллере PIC16F877.

Внешний вид проекта использования интерфейса I2C в микроконтроллере PIC16F877

Ранее на нашем сайте мы рассматривали использование интерфейса I2C в плате Arduino и в плате STM32F103C8 (Blue Pill).

Принципы работы протокола I2C

IIC (Inter Integrated Circuits), часто обозначаемый также как I2C, представляет собой двухпроводный синхронный коммуникационный протокол. Протокол I2C имеет две линии – линию данных (Serial Data Line, SDL) и линию синхронизации (Serial Clock Line, SCL)

Первоначально протокол I2C был разработан компанией Phillips. Протокол использует модель ведущий (Master) – ведомый (Slave). Связь в данном протоколе может осуществляться только между ведущим и ведомым. Достоинством протокола I2C по сравнению с ранее существовавшими до него аналогичными протоколами является то, что в нем к ведущему может быть подключен более чем один ведомый. Всего же протокол I2C поддерживает сеть размером до 128 устройств, каждое из которых имеет в сети уникальный адрес.

Структурная схема интерфейса I2C представлена на следующем рисунке.

Структурная схема интерфейса I2C

Обмен данными в протоколе I2C осуществляется с помощью двух линий – линии данных (SDL) и линии синхронизации (SCL).

В любой момент времени только ведущий (master) может инициировать связь (обмен данными). Поскольку в сети протокола может быть несколько ведомых (slave), то каждый из них должен иметь свой уникальный адрес, чтобы с его помощью ведущий мог указать какому ведомому предназначаются передаваемые им данные. В конкретный момент времени данные передает только тот ведомый, к которому обратился ведущий (по адресу), все остальные ведомые в это время "молчат". Таким образом, с использованием всего 2-х линий осуществляется связь между многочисленными устройствами.

Где применяется протокол I2C

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

Если вам нужна связь на большие расстояния чем те, которые может обеспечить протокол I2C, то вам необходимо использовать протокол RS232 или RS485, если же вам необходима более надежная связь на короткие расстояния, тогда вам целесообразно использовать протокол SPI.

I2C в микроконтроллере PIC16F877a с использованием компилятора XC8

В данном проекте мы будем рассматривать связь по протоколу I2C в микроконтроллере PIC16F877a только с использованием компилятора XC8. Данный процесс похож на аналогичные процессы и в других микроконтроллерах, но с небольшими отличиями. При этом стоит иметь ввиду, что "продвинутые" серии микроконтроллеров PIC, например, серия PIC18F в своем компиляторе уже содержит встроенную библиотеку для работы с протоколом I2C, но для микроконтроллера PIC16F877A такой библиотеки нет, поэтому мы создадим ее самостоятельно. Код данной библиотеки доступен для скачивания в конце данной статьи.

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

Далее рассмотрим функции, которые мы будем использовать в нашей библиотеке для работы с протоколом I2C в микроконтроллере PIC16F877A.

void I2C_Initialize()

Данная функция инициализации будет сообщать микроконтроллеру что мы будем использовать протокол I2C. Это осуществляется с помощью установки соответствующих битов в регистрах SSPCON и SSPCON2. Вначале нам необходимо задать режимы работы контактов, на которых мы будем использовать интерфейс IIC (у нас это контакты RC3 и RC4) на ввод данных. Затем установить необходимые биты в регистрах SSPCON и SSPCON2. Мы будем использовать режим ведущего в интерфейсе IIC с частотой синхронизации FOSC/(4 * (SSPADD + 1)). В комментариях к этим строкам программы указаны страницы в даташите на микроконтроллер, на которых подробно описаны эти настройки.

Далее нам необходимо установить частоту синхронизации (clock frequency), она может отличаться для различных приложений. Ее мы будем задавать с помощью переменной feq_k – изменяя в программе ее значение можно изменять частоту синхронизации.

Void I2C_Hold()

Данная функция используется для приостановки работы устройства до тех пор пока не завершится выполнение текущей операции I2C. Мы должны проверить завершение ее выполнения прежде чем переходить к новой операции. Это осуществляется с помощью проверки регистров SSPSTAT и SSPCON2. Регистр SSPSTAT содержит информацию о состоянии шины I2C. Указанные функции выполняются с помощью следующих команд:

С помощью данных команд мы убеждаемся в том, что 2-й бит регистра SSPSTAT установлен в 0, а биты с 0 по 4 регистра SSPCON2 также установлены в 0. Затем мы объединяем эти две команды в одну и проверяем результат получившейся операции. Если он равен 0, то программа продолжит выполнение, если он не равен 0, то выполнение программы задерживается до тех пор пока ее результат не будет равен 0.

Void I2C_Begin() и void I2C_End()

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

Void I2C_Write()

Данная функция используется для передачи данных от ведущего (master) к ведомому (slave). Эту функцию в большинстве случаев следует использовать после функции I2C_Begin(), а после ее выполнения вызывать функцию I2C_End(). Данные, которые будут передаваться по шине I2C, будут проходить через переменную data. Затем из этой переменной они будут перемещаться в буфер регистра SSPBUF чтобы затем передаться по шине I2C.

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

unsigned short I2C_Read()

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

Во время обмена данными по протоколу I2C ведомый после передачи данных, запрошенных ведущим, должен также передать бит подтверждения (acknowledgment bit). Этот бит должен быть проверен ведущим чтобы убедиться в том, что процесс обмена данными был успешным. После проверки бита подтверждения ACKDT мы будем устанавливать бит ACKEN.

Описанных нами функций вполне хватит для большинства операций обмена данными по интерфейсу I2C. Хотя функционал протокола I2C значительно больше чем в представленных нами функциях, мы не рассматриваем их здесь из-за ограниченного объема статьи. Для их более подробного изучения вы всегда можете обратиться к даташиту на микроконтроллер.

Полный код программы для работы с протоколом I2C в микроконтроллере PIC вы можете скачать по этой ссылке.

Начало программы для работы с протоколом I2C

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

Первым делом в программе установим биты конфигурации и установим тактовую частоту микроконтроллера равную 20 MHz.

Затем нам необходимо подключить заголовочный файл PIC16F877a_I2C.h, который можно скачать по ссылке, приведенной выше. Убедитесь в том, что заголовочный файл добавлен в заголовок вашего проекта. Структура файлов вашего проекта должна выглядеть как на следующем рисунке:

Структура файлов для нашего проекта

После этого подключите заголовочный файл в программе.

Далее внутри цикла while мы будем открывать соединение I2C и передавать по шине I2C несколько случайных данных, после этого мы будем закрывать соединение I2C. В качестве случайных значений мы выбрали D0, 88 и FF. Вы можете изменить их по своему усмотрению.

Моделирование работы проекта в Proteus

Симулятор Proteus имеет замечательный инструмент под названием I2C debugger, который можно использовать для считывания данных с шины I2C. Таким образом, с его помощью мы можем проверить передаваемые нами в шину I2C значения. Нарисованная в симуляторе Proteus схема нашего проекта приведена на следующем рисунке.

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

Информация о шине I2C в симуляторе Proteus

Если вы внимательно посмотрите на данные в этом окне, вы увидите что они те же самые, которые мы передавали в программе для микроконтроллера – D0, 88 и FF. Эти данные передаются каждую секунду, поэтому и время в данном окне будет обновляться соответствующим образом. Синяя стрелка показывает что данные передаются от ведущего к ведомому. Если данные будут передаваться в противоположном направлении, то стрелка будет направлена в другую сторону. Вид отдельно взятой строчки в этом окне выглядит следующим образом:

Тестирование работы проекта в симуляторе Proteus

Исходный код программы

Все файлы для данного проекта вы можете скачать по следующей ссылке.

Источник статьи

(Проголосуй первым!)
Загрузка...
686 просмотров

Комментарии

Использование интерфейса I2C в микроконтроллере PIC16F877 — 4 комментария

  1. Добрый день!Вы случайно не знаете, почему в i2c дебаггере вместо такой картинки, как у вас, появляется нечто подобное:
    324.601us 409.603us S Sr P
    409.603us 525.606us ? ? S P
    525.606us 645.404us ? ? ? ? S P
    645.404us 738.206us ? ? S P
    738.206us 1.001 s ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? S Sr P
    1.001 s 1.001 s ? ? S P
    1.001 s 1.001 s ? ? ? ? S P
    1.001 s 1.001 s ? ? S P
    1.001 s 1.001 s ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? S Sr P

    и т.д.?

    • Добрый день, точно не знаю. Но у вас вначале процесс идет нормально, а потом зацикливается почему то на 1 секунде. У вас конфигурация регистров правильно выставлена? Нет ли случайно где опечатки?

    • Да, случаются иногда небольшие изменения в терминологии. А SDI вы где увидели? Подскажите

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *