Программируем Arduino. Основы работы со скетчами
Шрифт:
Рис. 7.4. Временная диаграмма сигнала, передаваемого через интерфейс I2C
Ведущее устройство генерирует тактовые импульсы на линии SCL, и, когда имеются данные для передачи, отправитель (ведущее или ведомое устройство) выводит линию SDA из третьего состояния (в режим цифрового выхода) и посылает данные в виде логических нулей и единиц в моменты положительных импульсов тактового сигнала. По окончании передачи вывод тактовых импульсов может быть остановлен,
Библиотека Wire
Можно, конечно, генерировать описанные ранее импульсы самостоятельно, управляя битами, то есть включая и выключая цифровые выходы программно. Но чтобы упростить нам жизнь, в составе программного обеспечения для Arduino имеется библиотека Wire, принимающая на себя все сложности, связанные с синхронизацией, и позволяющая нам просто посылать и принимать байты данных.
Чтобы задействовать библиотеку Wire, ее сначала нужно подключить командой
#include <Wire.h>
Инициализация I2C
В большинстве случаев плата Arduino играет роль ведущего устройства на любой шине I2C. Чтобы инициализировать Arduino как ведущее устройство, нужно выполнить команду begin в функции setup, как показано далее:
void setup
{
Wire.begin;
}
Обратите внимание: поскольку в данном случае плата Arduino действует как ведущее устройство, ей не нужно присваивать адрес. Если бы плата настраивалась на работу в режиме ведомого устройства, нам пришлось бы присвоить адрес в диапазоне от 0 до 127, передав его как параметр, чтобы уникально идентифицировать плату на шине I2C.
Отправка данных ведущим устройством
Чтобы отправить данные устройству на шине I2C, сначала нужно выполнить функцию beginTransmission и передать ей адрес устройства-получателя:
Wire.beginTransmission(4);
Отправка данных устройствам на шине I2C может производиться побайтно или целыми массивами типа char, как показано в следующих двух примерах:
Wire.send(123); // передача байта со значением 123
Wire.send("ABC"); // передача строки символов "ABC"
По окончании передачи должна вызываться функция endTransmission:
Wire.endTransmission;
Прием данных ведущим устройством
Чтобы принять данные от ведомого устройства, сначала нужно указать количество ожидаемых байтов вызовом функции requestFrom:
Wire.requestFrom(4, 6); // запросить 6 байт у устройства с адресом 4
В первом аргументе этой функции передается адрес ведомого устройства, от которого ведущее устройство желает получить данные, а во втором аргументе — количество байтов, которое ожидается получить. Ведомое устройство может передать меньшее количество байтов, поэтому, чтобы определить, были ли получены данные и сколько байтов действительно получено, необходимо использовать функцию available. Следующий пример (взят из пакета примеров, входящих в состав библиотеки Wire) демонстрирует, как ведущее устройство принимает все полученные данные и выводит их в монитор последовательного порта:
#include <Wire.h>
void setup {
Wire.begin; // подключиться к шине i2c (для ведущего
// устройства адрес не указывается)
Serial.begin(9600); // инициализировать монитор последовательного порта
}
void loop {
Wire.requestFrom(8, 6); // запросить 6 байт у ведомого устройства #8
while (Wire.available) { // ведомое устройство может прислать меньше
char c = Wire.read; // принять байт как символ
Serial.print(c); // вывести символ
}
delay(500);
}
Библиотека Wire автоматически буферизует входящие данные.
Примеры использования I2C
Любое устройство I2C должно иметь сопроводительное техническое описание, где перечисляются поддерживаемые им сообщения. Такие описания необходимы, чтобы конструировать сообщения для отправки ведомым устройствам и интерпретировать их ответы. Однако для многих устройств I2C, которые можно подключить к плате Arduino, существуют специализированные библиотеки, обертывающие сообщения I2C в простые и удобные функции. Фактически, если вам придется работать с каким-то устройством, для которого отсутствует специализированная библиотека, опубликуйте собственную библиотеку для всеобщего использования и заработайте себе несколько очков в карму.
Даже если полноценная библиотека поддержки того или иного устройства отсутствует, часто в Интернете можно найти полезные фрагменты кода, демонстрирующие работу с устройством.
УКВ-радиоприемник TEA5767
В первом примере, демонстрирующем взаимодействие с устройством I2C, библиотека не используется. Здесь осуществляется обмен фактическими сообщениями между Arduino и модулем TEA5767. Данный модуль можно купить в Интернете очень недорого, он легко подключается к плате Arduino и используется как УКВ-приемник, управляемый Arduino.
Самый сложный этап — подключение устройства. Контактные площадки очень маленькие и расположены очень близко друг к другу, поэтому многие предпочитают смастерить или купить адаптер для подключения к плате.
На рис. 7.5 изображена схема подключения модуля к Arduino.
Рис. 7.5. Подключение модуля TEA5767 к плате Arduino Uno через интерфейс I2C
Техническое описание модуля TEA5767 можно найти по адресу www.sparkfun.com/datasheets/Wireless/General/TEA5767.pdf. Описание содержит массу технической информации, но, если пробежать взглядом по документу, можно заметить раздел с подробным описанием сообщений, распознаваемых устройством. В документации указывается, что TEA5767 принимает сообщения длиной 5 байт. Далее приводится полностью работоспособный пример, выполняющий настройку частоты сразу после запуска. На практике же обычно требуется несколько иной механизм настройки, например на основе кнопок и жидкокристаллического дисплея.
// sketch_07_01_I2C_TEA5767
#include <Wire.h>
void setup
{
Wire.begin;
setFrequency(93.0); // МГц
}
void loop
{
}
void setFrequency(float frequency)
{
unsigned int frequencyB = 4 * (frequency * 1000000 + 225000) / 32768;
byte frequencyH = frequencyB >> 8;
byte frequencyL = frequencyB & 0XFF;
Wire.beginTransmission(0x60);
Wire.write(frequencyH);
Wire.write(frequencyL);