Если устройство, с которым вы взаимодействуете, вам неподконтрольно и протоколом предполагается передача чисел в виде строк или полей данных переменной длины, то применение этих функций вполне оправданно. Но, если реализация протокола полностью находится в ваших руках, облегчите себе жизнь и откажитесь от ненужных сложностей, связанных с преобразованием типов и передачей сообщений в разных форматах.
Примеры, приведенные в разделе «Примеры использования последовательного интерфейса» далее в этой главе, можно использовать в качестве шаблонов при разработке своего кода, осуществляющего обмен данными.
Поддержка последовательного интерфейса включает массу функций, многие из которых вам никогда не понадобятся. Мы охватили здесь только самые необходимые. Информацию об остальных ищите в документации с описанием последовательного интерфейса Arduino по адресу http://arduino.cc/en/Reference/Serial 8.
Библиотека SoftwareSerial
Иногда, особенно при использовании модели Arduino Uno, единственного последовательного порта оказывается недостаточно. Библиотека SoftwareSerial позволяет использовать для последовательных взаимодействий практически любую пару контактов, хотя и с некоторыми ограничениями.
• С помощью SoftwareSerial невозможно принимать данные одновременно по нескольким портам.
• Если скетч использует таймеры или внешние прерывания, могут возникать проблемы.
Функции в библиотеке имеют те же имена, что и команды Serial, но продуманы лучше. Библиотека SoftwareSerial поддерживает последовательные взаимодействия с устройствами, использующими инвертированные сигналы, такими как дальномеры MaxSonar. Кроме того, создание объектов SoftwareSerial для соединений выполняется более ясным способом, чем стандартный подход с использованием номеров после слова Serial.
В табл. 10.2 перечислены контакты на платах Uno и Leonardo, которые может использовать библиотека SoftwareSerial. Если вы работаете с платой, имеющей четыре аппаратных последовательных порта, библиотека SoftwareSerial едва ли вам понадобится. Номера контактов без префикса A соответствуют цифровым входам/выходам.
Таблица 10.2. Контакты, доступные библиотеке SoftwareSerial
Модель | Контакты для линии Rx | Контакты для линии Tx |
---|---|---|
Uno | Любые, кроме 0 и 1 | Любые, кроме 0 и 1 |
Leonardo | Любые, кроме 0 и 1 | 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI) |
При создании объекта SoftwareSerial нужно передать два параметра с номерами контактов для линий Rx и Tx. Чтобы запустить взаимодействия, нужно вызвать функцию begin и передать ей скорость в бодах:
#include <SoftwareSerial.h>
SoftwareSerial mySerial(10, 11); // RX, TX
void setup()
{
mySerial.begin(9600);
mySerial.println("Hello, world?");
}
Полное описание библиотеки SoftwareSerial можно найти по адресу http://arduino.cc/en/Reference/SoftwareSerial 9.
Примеры использования последовательного интерфейса
В этом разделе демонстрируется несколько примеров использования УАПП и библиотеки SoftwareSerial.
Передача из компьютера в Arduino через USB
В первом примере демонстрируется применение монитора последовательного порта для передачи команд в плату Arduino. Раз в секунду Arduino будет посылать значение, прочитанное с аналогового входа A0, и одновременно ждать получения односимвольных команд g (go — вперед) и s (stop — стоп), управляющих передачей прочитанных значений. На рис. 10.3 изображено окно монитора последовательного порта с данными, полученными во время работы скетча.
Рис. 10.3. Окно монитора последовательного порта с данными, полученными от платы Arduino
В данном случае из-за того, что вывод производится непосредственно в окно монитора последовательного порта, данные, прочитанные с аналогового входа, передаются не в двоичном, а в текстовом виде.
Далее приводится скетч для этого примера:
// sketch_10_01_PC_to_Arduino
const int readingPin = A0;
boolean sendReadings = true;
void setup()
{
Serial.begin(9600);
}
void loop()
{
if (Serial.available())
{
char ch = Serial.read();
if (ch == 'g')
{
sendReadings = true;
}
else if (ch == 's')
{
sendReadings = false;
}
}
if (sendReadings)
{
int reading = analogRead(readingPin);
Serial.println(reading);
delay(1000);
}
}
Функция loop проверяет получение данных и, если они имеются, читает их по одному байту как символы. После полученный байт сравнивается с командами 's' и 'g', и переменной sendReadings присваивается соответствующее значение.
Затем по значению переменной sendReadings определяется необходимость чтения аналогового входа и вывода результатов. Если флаг sendReadings имеет значение true, перед отправкой следующего значения выполняется задержка на одну секунду.
Использование функции delay означает, что значение sendReadings сможет измениться только в следующей итерации функции loop. В данном скетче это не является проблемой, но в других ситуациях может потребоваться использовать другое решение, не блокирующее работу функции loop. Подробнее о подобных решениях рассказывается в главе 14.
Передача из Arduino в Arduino
Второй пример иллюстрирует передачу данных из одной платы Arduino Uno в другую. В данном случае одна плата Arduino передает значение, прочитанное с входа A1, другой плате, которая затем по этому значению определяет частоту мигания встроенного светодиода L.
На рис. 10.4 изображена схема соединения плат.
Рис. 10.4. Две платы Ardiono Uno взаимодействуют через последовательный порт
Контакт Tx на одной плате Arduino должен быть подключен к контакту Rx на другой и наоборот. В этом примере обе платы используют библиотеку SoftwareSerial, контакты 8 служат линией Rx, а контакты 9 — линией Tx.
Контакты GND обеих плат должны быть соединены. Чтобы плата-отправитель могла служить источником питания для платы-получателя, необходимо также соединить их контакты 5V. К плате-отправителю подключено переменное сопротивление, соединяющее гнезда A0 и A2. Настроив контакты A0 и A2 на работу в режиме цифровых выходов и установив на выходе A2 уровень HIGH, можно изменять уровень напряжения на контакте A1 в диапазоне от 0 до 5 В, вращая шток резистора, и тем самым управлять частотой мигания светодиода на другой плате Arduino.
Далее приводится скетч для платы-отправителя:
// sketch_10_02_Adruino_Sender
#include "SoftwareSerial.h"
const int readingPin = A1;
const int plusPin = A2;
const int gndPin = A0;
SoftwareSerial sender(8, 9); // RX, TX
void setup()
{
pinMode(gndPin, OUTPUT);
pinMode(plusPin, OUTPUT);
digitalWrite(plusPin, HIGH);
sender.begin(9600);
}
void loop()
{
int reading = analogRead(readingPin);
byte h = highByte(reading);
byte l = lowByte(reading);
sender.write(h);
sender.write(l);
delay(1000);
}
Перед отправкой прочитанное 16-битное значение (int) разбивается на старший и младший байты, затем оба байта посылаются в последовательный интерфейс командой write. Команды print и println преобразуют свой аргумент в строку, но команда write посылает байт