Как изменить адрес i2c устройства

Все модули серии «Flash» позволяют назначать себе адрес для шины I2C, который сохраняется в энергонезависимую память и действует даже после отключения питания. По умолчанию все модули серии «Flash» поставляются с адресом 0x09. Допускается указывать адреса в диапазоне: 7 < адрес < 127. Протокол шины I2C не допускает наличие устройств с одинаковым адресом.

Общие сведения:

Все модули серии «Flash» позволяют назначать себе адрес для шины I2C, который сохраняется в энергонезависимую память и действует даже после отключения питания. По умолчанию все модули серии «Flash» поставляются с адресом 0x09. Допускается указывать адреса в диапазоне: 7 < адрес < 127. Протокол шины I2C не допускает наличие устройств с одинаковым адресом.

Для работы с модулями серии «Flash» используются библиотеки. В каждой библиотеке предусмотрен метод смены адреса changeAddress(), но он будет работать только с тем модулем, для которого написана библиотека.

Изменить адрес любого I2C модуля серии «Flash» можно аппаратно, используя установщик адресов FLASH-I2C, или программно, используя библиотеку смены адресов iarduino_I2C_Address.

Примеры:

В данном разделе раскрыты примеры смены адреса при использовании библиотеки iarduino_Address. Сама библиотека содержит больше примеров, доступных из меню Arduino IDE: Файл / Примеры / iarduino I2C Address (установка I2C адресов).

Смена адреса одного модуля на шине I2C:

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

uint8_t newAddress = 0x09;                        // Назначаемый модулю адрес (0x07 < адрес < 0x7F).
                                                  //
#include <iarduino_I2C_Address.h>                 // Подключаем библиотеку для работы с адресами модулей линейки I2C-flash.
iarduino_I2C_Address j;                           // Объявляем объект j для работы с модулем I2C-flash. Адрес модуля будет определен автоматически.
                                                  // Если адрес модуля известен, то его можно указать при создании объекта, например, iarduino_I2C_Address j(0xA0);
void setup(){                                     //
     Serial.begin(9600);                          // Инициируем передачу данных по шине UART на скорости 9600 бит/сек.
     j.begin();                                   // Инициируем работу с модулем.
     while(!j){;}                                 // Запрещаем дальнейшую работу если модуль не инициализирован.
     Serial.print("Найден модуль 0x");            //
     Serial.println( j, HEX );                    // Выводим текущий адрес модуля.
     j=newAddress;                                // Меняем адрес модуля на newAddress.
     if(j==newAddress){                           // Проверяем новый адрес модуля.
         Serial.println("Адрес модуля изменён");  // Успех записи нового адреса можно проверить по результату присвоения: if( j=newAddress ){/*успешно*/;}else{/*провал*/;}
     }                                            // 
     Serial.print("Текущий адрес модуля 0x");     //
     Serial.println( j, HEX );                    //   Выводим текущий адрес модуля.
}                                                 //
                                                  //
void loop(){                                      //
}                                                 //

Для работы данного примера, на шине I2C должен быть только один модуль.

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

Смена адресов нескольких модулей:

Пример меняет адреса нескольких модулей сразу. Модулям с адресами 0xAB и 0xCD назначаются адреса 0x10 и 0x11 соответственно. На шине могут присутствовать и иные модули, адреса которых отличаются от указанных.

#include <iarduino_I2C_Address.h>                 // Подключаем библиотеку для работы с адресами модулей линейки I2C-flash.
iarduino_I2C_Address j[]={0xAB, 0xCD};            // Определяем массив объектов, указав текущие адреса модулей I2C-flash на шине I2C.
                                                  // 
void setup(){                                     //
     Serial.begin(9600);                          // Инициируем передачу данных по шине UART на скорости 9600 бит/сек.
//   Инициируем работу с модулями:                // Указанные действия можно выполнить в цикле.
     j[0].begin();                                // Инициализацию можно выполнять с проверкой: if( j[0].begin() ){/*успешно*/;}else{/*провал*/;}
     j[1].begin();                                //
//   Выводим старые адреса модулей на шине I2C:   // Указанные действия можно выполнить в цикле.
     Serial.println("Найдены модули:");           //
     if( j[0] ){ Serial.println( j[0] ); }        // Если модуль с адресом 0xAB не проинициализирован, то условие if(j[0]) не будет выполнено.
     if( j[1] ){ Serial.println( j[1] ); }        // Если модуль с адресом 0xCD не проинициализирован, то условие if(j[1]) не будет выполнено.
//   Указываем новые адреса модулям:              // Указанные действия можно выполнить в цикле.
     Serial.println("Меняем адреса модулей...");  // Важно назначать адреса, которых ещё нет на шине I2C!!!
     j[0]=0x10;                                   // Успех записи нового адреса можно проверить по результату присвоения:    if( j[0]= 0x10 ){/*успешно*/;}else{/*провал*/;}
     j[1]=0x11;                                   // Успех записи нового адреса можно проверить после присвоения: j[1]=0x11; if( j[1]==0x11 ){/*успешно*/;}else{/*провал*/;}
//   Выводим адреса модулей на шине I2C:          // Указанные действия можно выполнить в цикле.
     Serial.println("Новые адреса модулей:");     //
     if( j[0] ){ Serial.println( j[0] ); }        //
     if( j[1] ){ Serial.println( j[1] ); }        //
}                                                 //
                                                  //
void loop(){                                      //
}                                                 //

Для работы данного примера, на шине I2C должны присутствовать модули с адресами указанными при определении массива объектов j.

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

Если объявить массив объектов без указания адресов, например, iarduino_I2C_Address j[2]; то адреса будут определены автоматически. Нулевой элемент массива объектов будет работать с модулем имеющем наименьший адрес и далее по возрастанию. Если количество устройств на шине меньше чем количество элементов массива объектов, то «лишние» элементы массива не пройдут инициализацию и не пройдут проверку if( j[n] ).

Описание функций библиотеки:

В данном разделе описаны функции библиотеки iarduino_I2C_Address для работы с модулями серии Flash-I2C.

Данная библиотека может использовать как аппаратную, так и программную реализацию шины I2C. О том как выбрать тип шины I2C рассказано в статье Wiki — расширенные возможности библиотек iarduino для шины I2C.

Подключение библиотеки:

  • Если адрес модуля известен (в примере используется адрес 0x09):
#include <iarduino_I2C_Address.h>        // Подключаем библиотеку.
iarduino_Address obj(0x09);              // Создаём объект obj указав адрес модуля на шине I2C.
  • Если адрес модуля неизвестен (адрес будет найден автоматически):
#include <iarduino_I2C_Address.h>        // Подключаем библиотеку.
iarduino_Address obj;                    // Создаём объект obj без указания адреса.
  • Если адреса модулей известны (в примере используются адреса 0x0A, 0x0B, 0x0C):
#include <iarduino_I2C_Address.h>        // Подключаем библиотеку.
iarduino_Address obj[]={0x0A,0x0B,0x0C}; // Создаём массив объектов указав текущие адреса модулей на шине I2C.
  • Если адреса модулей неизвестны (адреса будут найдены автоматически):
#include <iarduino_I2C_Address.h>        // Подключаем библиотеку.
iarduino_Address obj[3];                 // Создаём массив объектов obj указав количество модулей.

При создании объекта без указания адреса, на шине должен находиться только один модуль.

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

Функция begin();

  • Назначение: Инициализация работы с модулем серии flash-I2C.
  • Синтаксис: begin();
  • Параметры: Нет.
  • Возвращаемое значение: bool — результат инициализации (true или false).
  • Примечание:
    • По результату инициализации можно определить наличие модуля на шине.
    • Функцию достаточно вызвать однократно, но обязательно до обращения к любым другим функциям объекта библиотеки.
  • Пример:
if( obj.begin() ){ Serial.print( "Модуль найден и инициирован!" ); }
else             { Serial.print( "Модуль не найден на шине I2C" ); }

Оператор присвоения адреса

  • Назначение: Смена адреса модуля на шине I2C.
  • Синтаксис: ОБЪЕКТ = АДРЕС.
  • Параметры: Нет.
  • Возвращаемое значение: bool — результат сохранения нового адреса (true или false).
  • Примечание: Вместо оператора «=» можно использовать функцию changeAddress().
  • Пример:
obj = 50; // Присвоение модулю адреса 50 без проверки сохранения адреса в модуль.
if( obj = 25 ){ Serial.print( "Присвоение адреса 25 с проверкой сохранения" ); }

Оператор получения адреса

  • Назначение: Запрос текущего адреса модуля на шине I2C.
  • Синтаксис: ПЕРЕМЕННАЯ = ОБЪЕКТ.
  • Параметры: Нет.
  • Возвращаемое значение: uint8_t — текущий адрес модуля.
  • Примечание: Вместо оператора «=» можно использовать функцию getAddress().
  • Пример:
uint8_t i = obj; // Получение текущего адреса модуля в переменную i.
if( obj == 25 ){ Serial.println( "Адрес модуля = 25" ); }
Serial.print( "Адрес модуля = " );
Serial.print( obj );

Операторы получения и присвоения адреса работают как операторы получения и присвоения значений переменным.

Дополнительные функции библиотеки:

Дополнительные функции позволяют работать с любыми модулями серии Flash-I2C.

Функция reset();

  • Назначение: Перезагрузка модуля.
  • Синтаксис: reset();
  • Параметры: Нет.
  • Возвращаемое значение: bool — результат перезагрузки (true или false).
  • Пример:
if( obj.reset() ){ Serial.print( "Модуль    перезагружен" ); }
else             { Serial.print( "Модуль не перезагружен" ); }

Функция changeAddress();

  • Назначение: Смена адреса модуля на шине I2C.
  • Синтаксис: changeAddress( АДРЕС );
  • Параметры:
    • uint8_t АДРЕС — новый адрес модуля на шине I2C (целое число от 0x08 до 0x7E)
  • Возвращаемое значение: bool — результат смены адреса (true или false).
  • Примечание: Вместо функции changeAddress() можно использовать оператор «=».
  • Пример:
if( obj.changeAddress(0x12) ){ Serial.print( "Адрес модуля изменён на 0x12" ); }
else                         { Serial.print( "Не удалось изменить адрес"    ); }

Функция getAddress();

  • Назначение: Запрос текущего адреса модуля на шине I2C.
  • Синтаксис: getAddress();
  • Параметры: Нет.
  • Возвращаемое значение: uint8_t АДРЕС — текущий адрес модуля на шине I2C (от 0x08 до 0x7E)
  • Примечание: Вместо функции getAddress() можно использовать оператор «=».
  • Пример:
Serial.print( "Адрес модуля на шине I2C = 0x");
Serial.println( obj.getAddress(), HEX );

Функция getVersion();

  • Назначение: Запрос версии прошивки модуля.
  • Синтаксис: getVersion();
  • Параметры: Нет
  • Возвращаемое значение: uint8_t ВЕРСИЯ — номер версии прошивки от 0 до 255.
  • Пример:
Serial.print( "Версия прошивки модуля ");
Serial.println( obj.getVersion(), HEX );

Функция setPullI2C();

  • Назначение: Управление внутрисхемной подтяжкой линий шины I2C.
  • Синтаксис: setPullI2C( [ФЛАГ] );
  • Параметры:
    • bool ФЛАГ требующий установить внутрисхемную подтяжку линий шины I2C (true или false).
  • Возвращаемое значение:
    • bool — результат включения / отключения внутрисхемной подтяжки (true или false).
  • Примечание:
    • Вызов функции без параметра равносилен вызову функции с параметром true — установить.
    • Флаг установки внутрисхемной подтяжки сохраняется в энергонезависимую память модуля, а значит будет действовать и после отключения питания.
    • Внутрисхемная подтяжка линий шины I2C осуществляется до уровня 3,3 В, но допускает устанавливать внешние подтягивающие резисторы и иные модули с подтяжкой до уровня 3,3 В или 5 В, вне зависимости от состояния внутрисхемной подтяжки модуля.
  • Пример:
if( obj.setPullI2C(true ) ){ Serial.print( "Внутрисхемная подтяжка установлена." ); }
if( obj.setPullI2C(false) ){ Serial.print( "Внутрисхемная подтяжка отключена."   ); }

Функция getPullI2C();

  • Назначение: Запрос состояния внутрисхемной подтяжки линий шины I2C.
  • Синтаксис: getPullI2C();
  • Параметры: Нет.
  • Возвращаемое значение: bool — ФЛАГ включения внутрисхемной подтяжки (true или false).
  • Пример:
if( obj.getPullI2C() ){ Serial.print( "Внутрисхемная подтяжка включена."  ); }
else                  { Serial.print( "Внутрисхемная подтяжка отключена." ); }

Ссылки:

  • Библиотека iarduino_I2C_Address.
  • Wiki — Расширенные возможности библиотек iarduino для шины I2C.
  • Wiki — Установка библиотек в Arduino IDE.

В этом уроке

  • Что такое I2C и в чем её удобство
  • Адресация модулей
  • Как изменить адрес модуля и почему это важно

Видео версия урока

Назначение и принцип работы шины I2C

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

Все модули, которые управляются по шине I2C, на самом деле соединены одним шлейфом. Это позволяет, используя всего два вывода контроллера, подключить к нему более сотни устройств! (Поясним: мотор подключен шиной из 4-х проводов: два из них — питание: + и -, и еще два — именно провода шины I2C, поэтому, можно сказать, что для управления модулем требуется всего два провода).

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

Если адреса устройств разные, то всё работает, как задумано: нужное устройство по нужному адресу выполняет предназначенные для него команды. Однако, если адреса устройств совпадают, то контроллер не сможет отличить модули друг от друга. Для того, чтобы всё работало, как задумано, каждый модуль в пределах одной шины должен иметь свой уникальный адрес.

Изменение I2C-адресов модулей

Изначально все наши модули имеют адрес 0х09, но, как мы уже знаем, все модули должны иметь разные адреса. Давайте сразу поменяем адреса всех модулей, с которыми будем работать. Для того, чтобы его изменить, воспользуйтесь скетчем ниже.

Важно! При изменении адреса к контроллеру должен быть подключен только один модуль.

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

Для этого потребуется открутить 4 винта и снять модуль питания, после чего достать контроллер.

*Шлейфы на картинке не показаны, их можно не отключать

После этого подключаем к контроллеру модуль правый мотор, как показано на рисунке (модуль с платы снимать не нужно):

Выводы модуля Выводы контроллера
GND GND
5V 5V
SDA A4
SCL A5

Все модули имеют одинаковые названия выводов и подключаются к контроллеру аналогично.

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

// ПРИМЕР СМЕНЫ АДРЕСА МОДУЛЯ I2C-FLASH:          // * Строки со звёздочкой являются необязательными
                                                  //
uint8_t newAddress = 0x0A;                        //   Назначаемый модулю адрес (0x07 < адрес < 0x7F)
                                                  //
#include <Wire.h>                                 // * Подключаем библиотеку для работы с аппаратной шиной I2C
#include <iarduino_I2C_Address.h>                 //   Подключаем библиотеку для работы с адресами модулей линейки I2C-flash
iarduino_I2C_Address j;                           //   Объявляем объект j для работы с модулем I2C-flash. Адрес модуля будет определен автоматически
                                                  //   Если адрес модуля известен, то его можно указать при создании объекта, например, iarduino_I2C_Address j(0xA0);
void setup(){                                     //
     delay(500);                                  // * Ждём завершения переходных процессов, связанных с подачей питания
     Serial.begin(9600);                          //
     while(!Serial){;}                            // * Ждём завершения инициализации шины UART
     j.begin();                                   //   Инициируем работу с модулем
     while(!j){;}                                 // * Запрещаем дальнейшую работу, если модуль не инициализирован
     Serial.print("Найден модуль 0x");            //
     Serial.println( j, HEX );                    //   Выводим текущий адрес модуля
     j=newAddress;                                //   Меняем адрес модуля на newAddress
     if(j==newAddress){                           // * Проверяем новый адрес модуля
         Serial.println("Адрес модуля изменён");  // * Успех записи нового адреса можно проверить по результату присвоения: if( j=newAddress ){/*успешно*/;}else{/*провал*/;}
     }                                            // * 
     Serial.print("Текущий адрес модуля 0x");     //
     Serial.println( j, HEX );                    //   Выводим текущий адрес модуля
}                                                 //
                                                  //
void loop(){                                      //
}                                                 //

Адреса для модулей:

Модуль Адрес
Правый мотор 0х0А
Левый мотор 0х0В
Бампер-датчик линии 0х0С
Матрица 8х8 0х0D

Больше устройств I2C на машинке не предвидится. Остальные модули работают не по шине I2C (они просто подключаются к выводам контроллера).

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

Измените таким же образом адреса всех модулей на указанные в таблице.

Теперь можно снова собрать машинку и двигаться дальше. Наши модули готовы к работе.

Проверка моторов

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

#include <Wire.h>                       // Подключаем библиотеку для работы с шиной I2C
#include <iarduino_I2C_Motor.h>         // Подключаем библиотеку для работы с мотором
iarduino_I2C_Motor  mot_R (0x0A);       // Объявляем объект mot_R для правого мотора с указанием адреса 0х0А
iarduino_I2C_Motor  mot_L (0x0B);       // Объявляем объект mot_L для левого мотора с указанием адреса 0х0В
void setup(){                         
  Serial.begin(9600);                                                           //  Инициируем работу монитора порта на скорости 9600 бод
  if (mot_R.begin()) Serial.println("Отлично, найден мотор с адресом 0x0A");    //  Инициируем работу с правым мотором. Если инициализация прошла успешно, выводим сообщение об успехе
  else Serial.println("Что-то не так... Мотор с адресом 0x0A не найден");       //  Иначе - сообщение об ошибке
  if (mot_L.begin()) Serial.println("Отлично, найден мотор с адресом 0x0B");    //  Инициируем работу с левым мотором. Если инициализация прошла успешно, выводим сообщение об успехе
  else Serial.println("Что-то не так... Мотор с адресом 0x0B не найден");       //  Иначе - сообщение об ошибке
}                                                
void loop(){                                    
}

Время прочтения
2 мин

Просмотры 12K

Приветствую всех жителей Хабра!

Хочу рассказать о новом и неожиданном способе подключения нескольких датчиков HTU21 по шине I2C без использования дополнительных микросхем.

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

Совсем недавно меня, как и многих пользователей, озадачило отсутствие возможности изменить адрес у данного датчика. Гугл, конечно же, выдал кучу статей о всяких мультиплексорах для шины I2C от «купить в известном всем китайском интернет-магазине» до «сделать схему своими руками». Нигде не было вариантов без паяльника и дополнительных расходов. Это не могло не расстроить так как нужно было решить проблему здесь и сейчас (заказчики такие заказчики). Хочу рассказать о более легком и непринужденном, очень простом выходе из данной ситуации. Заинтриговала? Тогда рассказываю.

Исходные данные: Arduino mega и 4 датчика HTU21.

Задача: необходимо подключить все датчики htu по шине I2C и считывать значения. Причем данные сенсоры — не единственные ведомые устройства на данной шине (в планах еще ЖК экран и другие датчики).

Что мы знаем? У датчика HTU21 фиксированный адрес на шине — 0x40 1. Как, имея микроконтроллер и 4 датчика с одинаковыми адресами на шине, обращаться к конкретному устройству без лишних микросхем?

Все оказывается довольно просто:

  1. подключаем землю, scl и sda как обычно (не забываем про подтягивающие резисторы для линии данных и синхронизации);
  2. подключаем провод питания каждого датчика к цифровому входу на Arduino (вы уже наверняка поняли куда я веду)
  3. поочередно подаем HIGH на каждый цифровой вход, питающий отдельный датчик и, после задержки, считываем значение с запитанного сенсора.
  4. подаем сигнал LOW для этого датчика и повторяем цикл для других сенсоров.

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

Не зря говорится, что все гениальное — просто!

Листинг прилагается:

/* функция, считывающая значение температуры
и влажности с датчиков HTU21 и датчика BME280 */

void greenhouseHT()
{  
    delay(30);
    rooms[3].TempA = bme.readTemperature();
    delay(30);
    rooms[3].HumA = bme.readHumidity(); 
    delay(30);  

  for (int i=0; i<3; i++)
  {
    digitalWrite(HTU21_pins[i], HIGH);
    delay(30);
    rooms[i].HumA   = myGreenhouseHumidity.readHumidity(); 
    rooms[i].TempA  = myGreenhouseHumidity.readTemperature(); 
    delay(30);
    digitalWrite(HTU21_pins[i], LOW);
    delay(30);
  }
  digitalWrite(pin_HTU21_1, HIGH);
}
  1. Приветствую. Начал разбираться с модулем GY-85 (гироскоп-акселерометр-магнетометр), хотелось бы подключить несколько модулей по одной шине, вопрос — могу ли я изменить адрес устройств что б они не конфликтовали друг с другом? Или есть другие решения? Спасибо

  2. Можете. Стандартная функция, в даташите устройства всё прописано.

  3. Спасибо огромное, а извиняюсь — наводку для новичка можно? Где искать, в каком направлении копать?

  4. Упс. То же спасибо за информацию… А способ есть, ну кроме ардуины на каждый модуль? Мне бы в максимуме опрашивать от 20ти до 40 датчиков, и все это от 25 раз в секунду

  5. Спасибо огромное, а извиняюсь — наводку для новичка можно? Где искать, в каком направлении копать?

  6. Не видел еще i2c устройства. в котором нету такой функции.

  7. Уважаемые знатоки, а можно резюме?
    1. Возможно ли менять адрес данного модуля и если можно то как?
    2. Пока (я не спец, пытаюсь разобраться) приходит понимание что например у гироскопа два заводских адреса, переключаются перемычкой….
    3. Если нет, есть ли какие либо решения подключения многих (20+) сенсоров GY-85 на одну шину что б к управляющей плате не тащить ворох проводов?

    Буду очень благодарен за подсказки

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

  9. Спасибо, буду пытаться. Обработку на базе планировал делать Orange Pi, а коммутировать ключами, что б к базе всего одна шина приходила. Все датчика с примерно одним шагом последовательно удалены от базы.

Иногда вам может понадобиться использовать с Ардуино более одного устройства с одним и тем же адресом I2C шины. Например, четыре OLED-дисплея для большого дисплея или семь датчиков температуры в инкубаторе.

Проблемы такого типа можно решить с помощью мультиплексора TCA9548A 1-to-8, и в этой статье мы рассмотрим, как это сделать с некоторыми примерами.

Приступая к работе

Во-первых, рассмотрим сам мультиплексор TCA9548A. TCA9548A — это шлюз между вашим Ардуино и восемью отдельными I2C шинами.

Стороны TCA9548A у вас есть одна шина с Ардуино. С другой стороны TCA9548A у вас есть восемь шин I2C, и только одна из них может быть подключена к Ардуино одновременно.

TCA9548 может функционировать при напряжении от 1,8 до 5 В и работать с устройствами, которые имеют рабочее напряжение от 1,8 до 5 В. Это очень удобно, так как, например,вы можете использовать устройства с питанием 3,3В с 5 вольтовой Ардуино. Итак, приступим.

Вставьте модуль в макетную плату и подключите его, как показано ниже:

Мы используем красные и синие линии питания макетной платы как 5В и GND соответственно. Подключим 5В и GND от Ардуино к линии питания макетной платы. Выводы A0, A1 и A2 подключим к GND, а A4/A5 к SDA/SCL соответственно к модулю:

подключение TCA9548

Электрические соединения следующие (модуль TCA9548 — Ардуино):

  • Vin к 5В
  • GND к GND
  • A0 к GND
  • A1 к GND
  • A2 к GND
  • SDA к A4
  • SCL к A5

Далее мы рассмотрим адрес I2C шины для TCA9548A. Используя схему подключения, показанную выше, адрес I2C шины будет 0x70. Вам нужно изменить его только в том случае, если одно из ваших устройств также имеет адрес 0x70.

Адрес I2C шины TCA9548A путем подключения контактов A0, A1 и A2 модуля TCA9548A. По умолчанию мы используем адрес 0x70, подключив A0…A2 к GND (низкий уровень сигнала). Используя ниже приведенную таблицу, вы можете изменить конфигурацию, выбрав необходимый адрес из диапазона 0x70…0x77:

Инвертор 12 В/ 220 В

Инвертор с чистой синусоидой, может обеспечивать питание переменно…

Изменение адреса I2C TCA9548A

Тестирование

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

Скопируйте и вставьте этот скетч в Ардуино IDE и загрузите его:

#include <Wire.h> 
void setup() {
  Wire.begin();
  Serial.begin(115200);
  Serial.println("nI2C Scanner");
} 
void loop() {
  byte error, address;
  int nDevices;
  Serial.println("Scanning...");
  nDevices = 0;
  for(address = 1; address < 127; address++ ) {
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
    if (error == 0) {
      Serial.print("I2C device found at address 0x");
      if (address<16) {
        Serial.print("0");
      }
      Serial.println(address,HEX);
      nDevices++;
    }
    else if (error==4) {
      Serial.print("Unknow error at address 0x");
      if (address<16) {
        Serial.print("0");
      }
      Serial.println(address,HEX);
    }    
  }
  if (nDevices == 0) {
    Serial.println("No I2C devices foundn");
  }
  else {
    Serial.println("donen");
  }
  delay(5000);          
}

Затем откройте монитор последовательного порта и установите скорость передачи данных 115200. Вы должны увидеть что-то вроде этого:

Как видите, наш сканер вернул адрес 0x70, что соответствует схеме подключения, описанной в таблице адресов шины, упомянутой ранее. Если вы не добились успеха, отключите Ардуино от компьютера и хорошенько проверьте проводку — затем попробуйте еще раз.

Управление селектором шины

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

Для этого мы отправляем байт данных в регистр шины TCA9548A, который указывает, какую из восьми шин мы хотим использовать. Каждый бит байта используется для включения или выключения определенной шины, причем MSB (старший значащий бит) — для шины 7 и LSB (младший значащий бит) — для шины 0.

Например, если вы отправили:

0b00000001 (в двоичном формате) — это активирует нулевую шину.

0b00010000 (в двоичном формате) — это активирует пятую шину.

Как только вы выбрали определенную шину, TCA9548A перенаправляет все данные из I2C Ардуино в эту шину.

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

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

void TCA9548A(uint8_t bus)
{
 Wire.beginTransmission(0x70); // TCA9548A адрес 0x70
 Wire.write(1 << bus); // отправляем байт на выбранную шину
 Wire.endTransmission();
}

Эта функция принимает номер шины и помещает «1» в регистр шины TCA9548A в соответствии с нашими требованиями. Затем вы просто вызываете эту функцию прямо перед тем, как потребуется получить доступ к устройству на определенной шине I2C. Например:

устройство на шине 0: TCA9548A (0)

устройство на шине 6: TCA9548A (6)

Краткое замечание о подтягивающих резисторах

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

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

Управляем нашим первым устройством

В качестве примера используем крошечный OLED-дисплей с диагональю 0,49 дюйма. Он имеет четыре контакта, которые необходимо подключить следующим образом (OLED — TCA9548A/Ардуино):

  • GND к GND
  • Vcc к Ардуино 3,3 В
  • CL к TCA9548A SC0 (шина № 0)
  • DA к TCA9548A SD0 (шина № 0)

OLED работает от 3,3В, поэтому мы запитываем его напрямую от вывода 3,3В Ардуино.

Теперь скопируйте и загрузите нижеприведенный скетч в Ардуино, и через мгновение на OLED-дисплее отобразятся некоторые числа, отсчитывающиеся в обратном порядке:

#include <Arduino.h>
#include <U8g2lib.h>
#include <Wire.h>

void TCA9548A(uint8_t bus)
{
 Wire.beginTransmission(0x70); // TCA9548A адрес 0x70
 Wire.write(1 << bus); // отправляем байт на выбранную шину
 Wire.endTransmission();
}

U8G2_SSD1306_64X32_1F_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

void setup()
{
 Wire.begin();
 u8g2.begin();
}

void loop()
{
 TCA9548A(0); // сообщаем TCA9548A, что мы хотим использовать I2C шину №0 (для связи с OLED)

 for (int a = 999; a >= 0; --a)
 {
 u8g2.clearBuffer(); // очищаем внутреннюю память
 u8g2.setFont(u8g2_font_inb24_mr ); // выбираем подходящий шрифт
 u8g2.setCursor(0, 24);
 u8g2.print(a);
 a = a - 47;
 u8g2.sendBuffer(); // выводим содержимое внутренней памяти дисплея
 delay(100);
 }
}

Как это работает? Мы вставили функцию выбора шины в строку 9 скетча, а затем вызвали функцию в строке 26, чтобы сообщить TCA9548A, что мы хотим использовать нулевую I2C шину. Затем остальная часть скетча – обычное использование OLED дисплея.

Управление двумя устройствами

Добавим еще одно устройство — модуль датчика атмосферного давления BMP180. Мы подключим его к седьмой I2C шине TCA5948A. В данном случае к предыдущей схеме нужно добавить еще два соединения, а именно (BMP180 — TCA9548A/Ардуино):

  • CL к TCA9548A SC7 (шина № 7)
  • DA к TCA9548A SD7 (шина № 7)

Теперь скопируйте и загрузите нижеприведенный скетч в Ардуино, и через мгновение на OLED дисплее появиться температура окружающей среды в целых градусах Цельсия:

#include <Arduino.h>
#include <U8g2lib.h>
#include <Adafruit_BMP085.h>
#include <Wire.h>

U8G2_SSD1306_64X32_1F_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
Adafruit_BMP085 bmp;
int temperature;

void TCA9548A(uint8_t bus)
{
Wire.beginTransmission(0x70); // TCA9548A адрес 0x70
Wire.write(1 << bus); // отправляем байт на выбранную шину
Wire.endTransmission();
}

void setup()
{
Wire.begin();
u8g2.begin();
TCA9548A(7); // выбираем I2C шину №7 для BMP180
if (!bmp.begin())
{
Serial.println("Could not find a valid BMP085 sensor, check wiring!");
while (1) {}
}
}

void loop()
{
// сначала получаем температуру от BMP180
TCA9548A(7); // выбираем I2C шину №7 для BMP180
temperature = int(bmp.readTemperature());

// далее отображаем температуру на OLED
TCA9548A(0); // выбираем I2C шину №0 для OLED
u8g2.clearBuffer(); // очищаем внутреннюю память
u8g2.setFont(u8g2_font_inb24_mr ); // выбираем подходящий шрифт
u8g2.setCursor(0, 24);
u8g2.print(temperature);
u8g2.sendBuffer();
delay(100);
}

Как это работает? Мы как обычно настраиваем библиотеки и необходимый код для OLED, BMP180 и TCA5948A.

Нам нужно инициализировать BMP180. Для этого сначала в строке 29 мы выбираем I2C шину №7 перед запуском BMP180.

В строке 40 мы снова запрашиваем I2C шину №7 у TCA9548A, а затем считываем температуру от BMP180. В строке 44 мы запрашиваем I2C шину №0 у TCA9548A, а затем отображаем температуру на OLED. Затем все повторяется снова.

Краткое примечание о контакте сброса

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

Теперь с помощью нашего рабочего примера вы можете понять, насколько легко использовать TCA9548A и получить доступ ко всем восьми шинам I2C через одну шину вашего Ардуино.

Тестер транзисторов / ESR-метр / генератор

Многофункциональный прибор для проверки транзисторов, диодов, тиристоров…

Понравилась статья? Поделить с друзьями:

Читайте также:

  • Как изменить адрес gmail аккаунта google
  • Как изменить адрес dns сервера на роутере
  • Как изменить адрес bitrix24
  • Как изменить адрес apple id на iphone
  • Как изменить адрес 5post на алиэкспресс

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии