Мастерство I2C связи с Arduino: Практический урок
В этом уроке мы узнаем, как работает протокол связи I2C, и также сделаем практический пример с платой Arduino и датчиком, использующим этот протокол. Вы можете посмотреть следующее видео или прочитать письменный урок ниже. Шина связи I2C очень популярна и широко используется многими электронными устройствами, потому что ее можно легко реализовать во многих электронных проектах, требующих связи между мастером и множеством ведомых устройств или даже множеством мастер-устройств. Легкая реализация обусловлена тем, что для связи между до почти 128 (112) устройств при 7-битной адресации и до почти 1024 (1008) устройств при 10-битной адресации требуется всего два провода. Как возможно общение между так большим количеством устройств всего с двумя проводами? Ну, у каждого устройства есть предустановленный ID или уникальный адрес устройства, поэтому мастер может выбирать, с какими устройствами будет общаться. Два провода, или линии, называются Serial Clock (SCL) и Serial Data (SDA). Линия SCL — это тактовый сигнал, который синхронизирует передачу данных между устройствами на шине I2C, и он генерируется мастер-устройством. Другая линия — SDA — несет данные. Обе линии являются «open-drain» (с открытым стоком), что означает, что к ним должны быть подключены подтягивающие резисторы, чтобы линии находились в высоком состоянии, потому что устройства на шине I2C активны в низком состоянии. Обычно используемые значения резисторов варьируются от 2К для более высоких скоростей около 400 кбит/с до 10К для более низких скоростей около 100 кбит/с. Сигнал данных передается последовательностями по 8 бит. Так, после специального условия старта идет первая 8-битная последовательность, указывающая адрес ведомого устройства, которому отправляются данные. После каждой 8-битной последовательности следует бит, называемый Acknowledge (подтверждение). После первого бита подтверждения в большинстве случаев идет еще одна адресная последовательность, но на этот раз для внутренних регистров ведомого устройства. Сразу после адресных последовательностей следуют последовательности данных в любом количестве до тех пор, пока данные не будут полностью отправлены, и заканчивается это специальным условием стопа. Давайте посмотрим еще ближе на эти события. Условие старта происходит, когда линия данных опускается в низкое состояние, пока линия такта все еще находится в высоком состоянии. После этого запускается такт, и каждый бит данных передается во время каждого тактового импульса. Последовательность адресации устройства начинается со старшего значащего бита (MSB) и заканчивается младшим значащим битом (LSB), и она фактически состоит из 7 бит, потому что 8-й бит используется для указания того, будет ли мастер записывать в ведомое (логический ноль) или читать из него (логическая единица). Следующий бит ACK/NACK используется ведомым устройством для указания того, успешно ли оно приняло предыдущую последовательность бит. В этот момент мастер-устройство передает управление линией SDA ведомому устройству, и если ведомое устройство успешно приняло предыдущую последовательность, оно притянет линию SDA вниз к условию, называемому Acknowledge. Если ведомое не притягивает линию SDA вниз, условие называется Not Acknowledge и означает, что оно не успешно приняло предыдущую последовательность, что может быть вызвано несколькими причинами. Например, ведомое может быть занято, может не понять полученные данные или команду, не может принять больше данных и так далее. В таком случае мастер-устройство решает, как будет продолжать. Далее идет адресация внутренних регистров. Внутренние регистры — это места в памяти ведомого, содержащие различную информацию или данные. Например, акселерометр ADX345 имеет уникальный адрес устройства и дополнительные адреса внутренних регистров для осей X, Y и Z. Так что если мы хотим прочитать данные оси X, сначала нам нужно отправить адрес устройства, а затем конкретный адрес внутреннего регистра для оси X. Эти адреса можно найти в даташите датчика. После адресации начинаются последовательности передачи данных либо от мастера, либо от ведомого в зависимости от выбранного режима на бите R/W. После того как данные полностью отправлены, передача заканчивается условием стопа, которое происходит, когда линия SDA переходит от низкого к высокому состоянию, пока линия SCL находится в высоком состоянии. В качестве примера я буду использовать плату расширения GY-80, состоящую из 5 разных датчиков, и плату расширения GY-521, состоящую из 3 разных датчиков. Так что мы можем получать данные с 8 разных датчиков всего с двумя проводами по шине I2C. Вы можете приобрести эти компоненты на любом из сайтов ниже: Вот как мы подключим платы. Вывод Serial Clock платы Arduino будет подключен к выводам Serial Clock двух плат расширения, то же самое для выводов Serial Data, и мы запитаем платы от выводов Gnd и 5V платы Arduino. Обратите внимание, здесь мы не используем подтягивающие резисторы, потому что платы расширения уже имеют их. Теперь, чтобы общаться с этими чипами или датчиками, нам нужно знать их уникальные адреса. Мы можем найти их в даташитах датчиков. Для платы расширения GY-80 у нас есть следующие 4 адреса: шестнадцатеричный 0x53 для 3-осевого акселерометра, шестнадцатеричный 0x69 для 3-осевого гироскопа, шестнадцатеричный 0x1E для 3-осевого магнетометра и шестнадцатеричный 0x77 для барометра и термометра. Для платы расширения GY-521 у нас есть только один адрес — шестнадцатеричный 0x68. Мы также можем получить или проверить адреса, используя скетч Arduino I2C Scanner, который можно найти на официальном сайте Arduino. Так что если мы загрузим и запустим этот скетч, мы получим адреса подключенных устройств на шине I2C. После того как мы нашли адреса устройств, нам также нужно найти адреса их внутренних регистров, чтобы читать данные из них. Например, если мы хотим прочитать данные для оси X с 3-осевого акселерометра платы GY-80, нам нужно найти адрес внутреннего регистра, где хранятся данные оси X. Из даташита датчика мы видим, что данные для оси X фактически хранятся в двух регистрах: DATAX0 с шестнадцатеричным адресом 0x32 и DATAX1 с шестнадцатеричным адресом 0x33. Теперь давайте сделаем код, который получит данные для оси X. Мы будем использовать библиотеку Arduino Wire, которую нужно включить в скетч. Здесь сначала нам нужно определить адрес датчика и адреса двух внутренних регистров, которые мы нашли ранее. Функция Wire.begin() инициализирует библиотеку Wire, и нам также нужно инициализировать последовательную коммуникацию, потому что мы будем использовать монитор последовательного порта для отображения данных с датчика. В loop() мы начнем с функции Wire.beginTransmission(), которая начнет передачу к конкретному датчику — в нашем случае 3-осевому акселерометру. Затем с функцией Wire.write() мы запросим конкретные данные из двух регистров оси X. Wire.endTransmission() завершит передачу и передаст данные из регистров. Теперь с функцией Wire.requestFrom() мы запросим переданные данные или два байта из двух регистров. Функция Wire.available() вернет количество байтов, доступных для чтения, и если это число совпадает с нашими запрошенными байтами, в нашем случае 2 байта, используя функцию Wire.read() мы прочитаем байты из двух регистров оси X. В конце мы выведем данные в монитор последовательного порта. Вот эти данные, но имейте в виду, что это сырые данные, и для получения правильных значений оси X нужно сделать некоторую математику. Вы можете найти больше деталей об этом в моем следующем уроке по использованию акселерометров с Arduino, потому что я не хочу перегружать этот урок, так как его главная цель — объяснить, как работает Arduino I2C связь.Обзор

Как работает I2C

Протокол I2C



Пример


Часть датчика I2C Адрес 3-осевой акселерометр Analog Devices ADXL345 0x53 3-осевой гироскоп ST Microelectronics L3G4200D 0x69 3-осевой магнетометр Honeywell MC5883L 0x1E Барометр + Термометр Bosch BMP085 0x77
Код Arduino I2C
/*
* Как работает протокол связи I2C - Урок Arduino I2C
* by Dejan, www.HowToMechatronics.com
*/
#include <Wire.h>
int ADXLAddress = 0x53; // Адрес устройства с 8-м битом для выбора режима (чтение)
#define X_Axis_Register_DATAX0 0x32 // Шестнадцатеричный адрес внутреннего регистра DATAX0.
#define X_Axis_Register_DATAX1 0x33 // Шестнадцатеричный адрес внутреннего регистра DATAX1.
#define Power_Register 0x2D // Регистр управления питанием
int X0,X1,X_out;
void setup() {
Wire.begin(); // Инициализация библиотеки Wire
Serial.begin(9600); delay(100);
// Включение измерения
Wire.beginTransmission(ADXLAddress);
Wire.write(Power_Register); // Бит D3 высокий для включения измерения (0000 1000)
Wire.write(8);
Wire.endTransmission();
}
void loop() {
Wire.beginTransmission(ADXLAddress); // Начало передачи к датчику
// Запрос конкретных регистров для данных
Wire.write(X_Axis_Register_DATAX0); Wire.write(X_Axis_Register_DATAX1);
Wire.endTransmission(); // Завершает передачу и передает данные из двух регистров
Wire.requestFrom(ADXLAddress,2); // Запрашивает переданные два байта из двух регистров
if(Wire.available()<=2) {
// X0 = Wire.read(); // Читает данные из регистра
X1 = Wire.read();
}
Serial.print("X0= "); Serial.print(X0);
Serial.print(" X1= "); Serial.println(X1);
}Язык кода: Arduino (arduino)
Производственный процесс
- Бесшовная I2C-интеграция Arduino и Raspberry Pi 2 для IoT-проектов с датчиками
- Создание надежного монитора энергии и логгера данных на Arduino — пошаговое руководство
- Логгер температуры и влажности на Arduino с DHT11 и Ethernet Shield
- Управление Arduino Uno из Python 3: команды через последовательный порт и демонстрация с LED
- Подключение Arduino к NMEA-0183: пошаговое руководство
- Сборка домашней автоматизации JARVIS v1 на Arduino Nano — пошаговое руководство
- Мастер-класс по многопоточности Arduino с протопотоками: пошаговое руководство
- Мастерство nRF24L01: беспроводная связь, интеграция с Arduino, схемы и код
- Мастер-класс по MPU6050: акселерометр и гироскоп для Arduino
- Отслеживание ориентации с Arduino и акселерометром ADXL345