Программируем Arduino. Основы работы со скетчами
Шрифт:
Wire.write(0xB0);
Wire.write(0x10);
Wire.write(0x00);
Wire.endTransmission;
delay(100);
}
Весь код, представляющий для нас интерес в этом примере, находится в функции setFrequency. Она принимает вещественное число — частоту в мегагерцах. То есть, если вы пожелаете собрать и опробовать этот проект, узнайте частоту, на которой вещает местная радиостанция с хорошим сильным сигналом, и вставьте ее значение в вызов setFrequency в функции setup.
Чтобы преобразовать вещественное значение частоты в
unsigned int frequencyB = 4 * (frequency * 1000000 + 225000) / 32768;
byte frequencyH = frequencyB >> 8;
byte frequencyL = frequencyB & 0XFF;
Команда >> сдвигает биты вправо, то есть операция >> 8 сдвинет старшие 8 бит в сторону младших на 8 двоичных разрядов. Оператор & выполняет поразрядную операцию И (AND), которая в данном случае сбросит старшие 8 бит и оставит только младшие. Более полное обсуждение операций с битами вы найдете в главе 9.
Остальной код в функции setFrequency инициализирует передачу сообщения I2C ведомому устройству с адресом 0x60, который закреплен за приемником TEA5767. Затем осуществляется последовательная передача 5 байт, начиная с 2 байт частоты.
Прочитав документацию, вы узнаете о множестве других возможностей, доступных посредством разных сообщений, например о сканировании диапазона, выключении одного или двух каналов вывода звука и выборе режима моно/стерео.
В приложении мы еще вернемся к этому примеру и создадим библиотеку для Arduino, чтобы упростить работу с модулем TEA5767.
Взаимодействие между двумя платами Arduino
Во втором примере используются две платы Arduino, одна действует как ведущее устройство I2C, а другая — как ведомое. Ведущее устройство будет посылать сообщения ведомому, которое, в свою очередь, будет выводить их в монитор последовательного порта, чтобы можно было наглядно убедиться, что схема работает.
Схема соединения плат для этого примера показана на рис. 7.6. Обратите внимание на то, что модуль TEA5767 имеет встроенные подтягивающие сопротивления на линиях I2C. Однако в данном случае, когда друг к другу подключаются две платы Arduinos, такие резисторы отсутствуют, поэтому понадобится включить свои сопротивления с номиналом 4,7 кОм (рис. 7.6).
Рис. 7.6. Соединение двух плат Arduino через интерфейс I2C
В платы должны быть загружены разные скетчи. Оба скетча включены в состав примеров для библиотеки Wire. Программа для ведущей платы Arduino находится в меню File—>Example—>Wire—>master_writer (Файл—> Примеры—>Wire—>master_writer), а для ведомой платы — в меню File—> Example—>Wire—>slave_receiver (Файл—>Примеры—>Wire—>slave_receiver).
Запрограммировав
Начнем со скетча в ведущей плате:
#include <Wire.h>
void setup {
Wire.begin; // подключиться к шине i2c (для ведущего устройства
// адрес не указывается)
}
byte x = 0;
void loop {
Wire.beginTransmission(4); // инициализировать передачу устройству #4
Wire.write("x is "); // послать 5 байт
Wire.write(x); // послать 1 байт
Wire.endTransmission; // остановить передачу
x++;
delay(500);
}
Этот скетч генерирует сообщение вида x is 1, где 1 — число, увеличивающееся каждые полсекунды. Затем сообщение посылается ведомому устройству с адресом 4, как определено в вызове beginTransmission.
Задача ведомого скетча — принять сообщение от ведущего устройства и вывести его в монитор последовательного порта:
#include <Wire.h>
void setup {
Wire.begin(4); // подключиться к шине i2c с адресом #4
Wire.onReceive(receiveEvent); // зарегистрировать обработчик события
Serial.begin(9600); // открыть монитор последовательного порта
}
void loop {
delay(100);
}
// эта функция вызывается всякий раз, когда со стороны ведущего устройства
// поступают очередные данные, эта функция зарегистрирована как обработчик
// события, см. setup
void receiveEvent(int howMany) {
while (1 < Wire.available) { // цикл по всем принятым байтам, кроме
// последнего
char c = Wire.read; // прочитать байт как символ
Serial.print(c); // вывести символ
}
int x = Wire.read; // прочитать байт как целое число
Serial.println(x); // вывести целое число
}
Первое, на что следует обратить внимание в этом скетче, — функции Wire.begin передается параметр 4. Он определяет адрес ведомого устройства на шине I2C, в данном случае 4. Он должен соответствовать адресу, который используется ведущим устройством для отправки сообщений.
СОВЕТ
К одной двухпроводной шине можно подключить множество ведомых плат Arduino при условии, что все они будут иметь разные адреса I2C.
Скетч для ведомой платы отличается от скетча для ведущей платы, потому что использует прерывания для приема сообщений, поступающих от ведущего устройства. Установка обработчика сообщений выполняется функцией onReceive, которая вызывается подобно подпрограммам обработки прерываний (глава 3). Вызов этой функции нужно поместить в функцию setup, чтобы обеспечить вызов пользовательской функции receiveEvent при получении любых поступающих сообщений.