Библиотека SoftwareSerial
Библиотека SoftwareSerial позволяет организовать последовательную связь на любых цифровых пинах Arduino, программно эмулируя аппаратный UART.
Библиотека SoftwareSerial позволяет организовать последовательную связь на любых цифровых пинах Arduino, программно воспроизводя функциональность аппаратного UART (отсюда и название — «SoftwareSerial»). Можно создать несколько программных последовательных портов со скоростью до 115200 бод. Специальный параметр включает инверсию сигнала для устройств, которые этого требуют.
Версия SoftwareSerial, включённая начиная с Arduino IDE 1.0, основана на библиотеке NewSoftSerial library авторства Mikal Hart.
Чтобы подключить библиотеку к проекту:
#include <SoftwareSerial.h>
Когда это нужно
Аппаратных UART на большинстве плат Arduino немного: на Uno и Nano — всего один, и он занят USB-соединением с компьютером. Если нужно одновременно работать с монитором порта и, например, с GPS-модулем или Bluetooth-адаптером — SoftwareSerial становится незаменимым инструментом. Библиотека работает на любых цифровых пинах с поддержкой прерываний по изменению состояния.
Ограничения библиотеки
Прежде чем использовать SoftwareSerial, важно понимать её ограничения:
Одновременная передача и приём данных невозможны. При нескольких программных портах только один может принимать данные в каждый момент времени. На платах Mega и Mega 2560 не все пины поддерживают прерывания по изменению состояния. Для RX можно использовать только: 10, 11, 12, 13, 14, 15, 50, 51, 52, 53, A8 (62), A9 (63), A10 (64), A11 (65), A12 (66), A13 (67), A14 (68), A15 (69). На платах Leonardo и Micro для RX подходят только пины: 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI). На Arduino / Genuino 101 максимальная скорость приёма — 57600 бод. На Arduino / Genuino 101 приём не работает на цифровом пине 13.
Если проект требует одновременного обмена данными через несколько портов, обратите внимание на библиотеку AltSoftSerial library от Paul Stoffregen — она лишена многих из перечисленных ограничений.
Примеры
SoftwareSerial example: когда одного последовательного порта не хватает. Two port receive: работа с несколькими программными последовательными портами одновременно.
Методы
SoftwareSerial()
Создаёт экземпляр объекта SoftwareSerial. Можно создать несколько объектов SoftwareSerial, однако активно слушать входящие данные в каждый момент может только один из них.
Синтаксис
SoftwareSerial(rxPin, txPin, inverse_logic)
Параметры
_rxPin_: пин, на котором принимаются последовательные данные (RX). _txPin_: пин, на котором передаются последовательные данные (TX). * _inverse_logic_: инверсия логики входящих битов (по умолчанию — обычная логика). Если установлен в true, библиотека SoftwareSerial воспринимает LOW (0 В на пине, в норме — состояние покоя) как бит «1», а HIGH (5 В на пине) — как бит «0». Это также влияет на запись в TX-пин. Значение по умолчанию — false.
Возвращаемое значение
Нет.
Пример
#include <SoftwareSerial.h>
const byte rxPin = 2;
const byte txPin = 3;
// Создаём новый объект SoftwareSerial
SoftwareSerial mySerial (rxPin, txPin);
См. также
available() begin() isListening() overflow() peek() read() print() println() listen() write()
---
available()
Возвращает количество байт (символов), доступных для чтения из буфера программного последовательного порта. Это данные, которые уже получены и сохранены в буфере приёма.
Синтаксис
mySerial.available()
Параметры
Нет.
Возвращаемое значение
Количество байт, готовых к чтению.
Пример
#include <SoftwareSerial.h>
#define rxPin 10
#define txPin 11
// Создаём новый объект SoftwareSerial
SoftwareSerial mySerial = SoftwareSerial(rxPin, txPin);
void setup() {
// Задаём режимы пинов TX и RX
pinMode(rxPin, INPUT);
pinMode(txPin, OUTPUT);
// Устанавливаем скорость передачи для объекта SoftwareSerial
mySerial.begin(9600);
}
void loop() {
if (mySerial.available() > 0) {
mySerial.read();
}
}
Практическое замечание
Проверяйте available() перед вызовом read(), чтобы не получить -1 при пустом буфере. Типичный паттерн: while (mySerial.available()) { char c = mySerial.read(); ... }.
См. также
SoftwareSerial() begin() isListening() overflow() peek() read() print() println() listen() write()
---
begin()
Устанавливает скорость (бод) для последовательной связи. Поддерживаемые скорости: 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 31250, 38400, 57600 и 115200 бод.
Синтаксис
mySerial.begin(speed)
Параметры
* _speed_: желаемая скорость передачи данных (тип long). Поддерживаемые значения: 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 31250, 38400, 57600, 115200 бод.
Возвращаемое значение
Нет.
Пример
#include <SoftwareSerial.h>
#define rxPin 10
#define txPin 11
// Создаём новый объект SoftwareSerial
SoftwareSerial mySerial = SoftwareSerial(rxPin, txPin);
void setup() {
// Задаём режимы пинов TX и RX
pinMode(rxPin, INPUT);
pinMode(txPin, OUTPUT);
// Устанавливаем скорость передачи для объекта SoftwareSerial
mySerial.begin(9600);
}
void loop() {
// ...
}
Практическое замечание
При высоких скоростях (57600 и выше) программная реализация UART чувствительна к загруженности процессора. Если в loop() есть долгие задержки или тяжёлые вычисления — возможны потери байт. Для надёжной работы на 115200 бод используйте минимальный код в основном цикле.
См. также
SoftwareSerial() available() isListening() overflow() peek() read() print() println() listen() write()
---
isListening()
Проверяет, активно ли прослушивает данный программный последовательный объект.
Синтаксис
mySerial.isListening()
Параметры
Нет.
Возвращаемое значение
Boolean: true, если объект сейчас прослушивает входящие данные.
Пример
#include <SoftwareSerial.h>
// Создаём новый объект SoftwareSerial: RX на цифровом пине 10, TX на цифровом пине 11
SoftwareSerial portOne(10, 11);
void setup() {
// Устанавливаем скорость передачи для порта Serial
Serial.begin(9600);
// Устанавливаем скорость передачи для объекта SerialSoftware
portOne.begin(9600);
}
void loop() {
if (portOne.isListening()) {
Serial.println("portOne is listening!");
}
// ...
См. также
SoftwareSerial() available() begin() overflow() peek() read() print() println() listen() write()
---
overflow()
Проверяет, произошло ли переполнение буфера SoftwareSerial. Вызов этой функции сбрасывает флаг переполнения — то есть последующие вызовы вернут false, если за это время не поступил ещё один лишний байт. Буфер SoftwareSerial вмещает до 64 байт.
Синтаксис
mySerial.overflow()
Параметры
Нет.
Возвращаемое значение
Boolean: true, если переполнение произошло.
Пример
#include <SoftwareSerial.h>
// Создаём новый объект SoftwareSerial: RX на цифровом пине 10, TX на цифровом пине 11
SoftwareSerial portOne(10, 11);
void setup() {
// Устанавливаем скорость передачи для порта Serial
Serial.begin(9600);
// Устанавливаем скорость передачи для объекта SerialSoftware
portOne.begin(9600);
}
void loop() {
if (portOne.overflow()) {
Serial.println("portOne overflow!");
}
// ...
Типичные ошибки
Переполнение буфера — частая проблема при работе с GPS или другими модулями, которые непрерывно шлют данные. Если overflow() возвращает true, значит данные читаются недостаточно быстро. Решение: увеличить частоту опроса available() или уменьшить скорость передачи на стороне источника.
См. также
SoftwareSerial() available() begin() isListening() peek() read() print() println() listen() write()
---
peek()
Возвращает символ, принятый на RX-пине программного последовательного порта. В отличие от read(), повторные вызовы peek() возвращают тот же самый символ — он остаётся в буфере. Обратите внимание: одновременно принимать данные может только один объект SoftwareSerial (выбирается с помощью listen()).
Синтаксис
mySerial.peek()
Параметры
Нет.
Возвращаемое значение
Прочитанный символ или -1, если данных нет.
Пример
#include <SoftwareSerial.h>
// Создаём новый объект SoftwareSerial: RX на цифровом пине 10, TX на цифровом пине 11
SoftwareSerial mySerial(10, 11);
void setup() {
// Устанавливаем скорость передачи для объекта SerialSoftware
mySerial.begin(9600);
}
void loop() {
char c = mySerial.peek();
}
См. также
SoftwareSerial() available() begin() isListening() overflow() read() print() println() listen() write()
---
read()
Возвращает символ, принятый на RX-пине объекта SoftwareSerial, и извлекает его из буфера. Одновременно принимать данные может только один объект SoftwareSerial (выбирается с помощью listen()).
Синтаксис
mySerial.read()
Параметры
Нет.
Возвращаемое значение
Прочитанный символ или -1, если данных нет.
Пример
#include <SoftwareSerial.h>
// Создаём новый объект SoftwareSerial: RX на цифровом пине 10, TX на цифровом пине 11
SoftwareSerial mySerial(10, 11);
void setup() {
// Устанавливаем скорость передачи для объекта SerialSoftware
mySerial.begin(9600);
}
void loop() {
char c = mySerial.read();
}
См. также
SoftwareSerial() available() begin() isListening() overflow() peek() print() println() listen() write()
---
print()
Передаёт данные через TX-пин объекта SoftwareSerial. Работает так же, как функция print() объекта Serial.
Синтаксис
mySerial.print(val)
Параметры
* _val_: значение для вывода.
Возвращаемое значение
Количество записанных байт (считывать это значение необязательно).
Пример
#include <SoftwareSerial.h>
// Создаём новый объект SoftwareSerial: RX на цифровом пине 10, TX на цифровом пине 11
SoftwareSerial mySerial(10, 11);
int analogValue;
void setup() {
// Устанавливаем скорость передачи для объекта SerialSoftware
mySerial.begin(9600);
}
void loop() {
// Считываем аналоговое значение с пина A0
analogValue = analogRead(A0);
// Выводим analogValue в Serial Monitor в различных форматах:
mySerial.print(analogValue); // Вывод в виде десятичного числа в ASCII-кодировке
mySerial.print("\t"); // Вывод символа табуляции
mySerial.print(analogValue, DEC); // Вывод в виде десятичного числа в ASCII-кодировке
mySerial.print("\t"); // Вывод символа табуляции
mySerial.print(analogValue, HEX); // Вывод в виде шестнадцатеричного числа в ASCII-кодировке
mySerial.print("\t"); // Вывод символа табуляции
mySerial.print(analogValue, OCT); // Вывод в виде восьмеричного числа в ASCII-кодировке
mySerial.print("\t"); // Вывод символа табуляции
mySerial.print(analogValue, BIN); // Вывод в виде двоичного числа в ASCII-кодировке
mySerial.print("\t"); // Вывод символа табуляции
mySerial.print(analogValue/4, BYTE); // Вывод как сырое байтовое значение (делим
// на 4, потому что analogRead() возвращает числа
// от 0 до 1023, а байт может хранить значения только до 255)
mySerial.print("\t"); // Вывод символа табуляции
mySerial.println(); // Вывод символа перевода строки
// Пауза 10 миллисекунд перед следующим считыванием
delay(10);
}
См. также
SoftwareSerial() available() begin() isListening() overflow() peek() read() print() println() listen() * write()
---
println()
Передаёт данные через TX-пин объекта SoftwareSerial с добавлением символов возврата каретки и перевода строки в конце. Работает так же, как функция println() объекта Serial.
Синтаксис
mySerial.println(val)
Параметры
* _val_: значение для вывода.
Возвращаемое значение
Количество записанных байт (считывать это значение необязательно).
Пример
#include <SoftwareSerial.h>
// Создаём новый объект SoftwareSerial: RX на цифровом пине 10, TX на цифровом пине 11
SoftwareSerial mySerial(10, 11);
int analogValue;
void setup() {
// Устанавливаем скорость передачи для объекта SerialSoftware
mySerial.begin(9600);
}
void loop() {
// Считываем аналоговое значение с пина A0
analogValue = analogRead(A0);
// Выводим analogValue в Serial Monitor в различных форматах:
mySerial.print(analogValue); // Вывод в виде десятичного числа в ASCII-кодировке
mySerial.print("\t"); // Вывод символа табуляции
mySerial.print(analogValue, DEC); // Вывод в виде десятичного числа в ASCII-кодировке
mySerial.print("\t"); // Вывод символа табуляции
mySerial.print(analogValue, HEX); // Вывод в виде шестнадцатеричного числа в ASCII-кодировке
mySerial.print("\t"); // Вывод символа табуляции
mySerial.print(analogValue, OCT); // Вывод в виде восьмеричного числа в ASCII-кодировке
mySerial.print("\t"); // Вывод символа табуляции
mySerial.print(analogValue, BIN); // Вывод в виде двоичного числа в ASCII-кодировке
mySerial.print("\t"); // Вывод символа табуляции
mySerial.print(analogValue/4, BYTE); // Вывод как сырое байтовое значение (делим
// на 4, потому что analogRead() возвращает числа
// от 0 до 1023, а байт может хранить значения только до 255)
mySerial.print("\t"); // Вывод символа табуляции
mySerial.println(); // Вывод символа перевода строки
// Пауза 10 миллисекунд перед следующим считыванием
delay(10);
}
См. также
SoftwareSerial() available() begin() isListening() overflow() peek() read() print() listen() write()
---
listen()
Активирует прослушивание для выбранного объекта SoftwareSerial. В каждый момент слушать может только один объект SoftwareSerial; данные, поступающие на другие порты, будут отброшены. Данные, уже принятые текущим активным портом, при вызове listen() также теряются — если только не вызывается listen() на уже активном объекте.
Синтаксис
mySerial.listen()
Параметры
Нет.
Возвращаемое значение
true, если вызов заменил другой активный порт.
Пример
#include <SoftwareSerial.h>
// Создаём новый объект SoftwareSerial: RX на цифровом пине 10, TX на цифровом пине 11
SoftwareSerial portOne(10, 11);
// Создаём новый объект SoftwareSerial: RX на цифровом пине 8, TX на цифровом пине 9
SoftwareSerial portTwo(8, 9);
void setup() {
// Устанавливаем скорость передачи для объекта Serial
Serial.begin(9600);
// Устанавливаем скорость передачи для объектов SerialSoftware
portOne.begin(9600);
portTwo.begin(9600);
}
void loop() {
// Активируем прослушивание объекта SoftwareSerial
portOne.listen();
if (portOne.isListening()) {
Serial.println("portOne is listening!");
} else {
Serial.println("portOne is not listening!");
}
if (portTwo.isListening()) {
Serial.println("portTwo is listening!");
} else {
Serial.println("portTwo is not listening!");
}
}
Практическое замечание
При работе с двумя и более программными портами удобно переключаться между ними через listen() по таймеру или по событию — например, сначала считать пакет с одного устройства, затем переключиться на другое. Помните, что данные, пришедшие на «молчащий» порт, безвозвратно теряются.
См. также
SoftwareSerial() available() begin() isListening() overflow() peek() read() print() println() write()
---
write()
Передаёт данные через TX-пин объекта SoftwareSerial в виде сырых байт. Работает так же, как функция write() объекта Serial.
Синтаксис
mySerial.write(val)
Параметры
* _val_: двоичное значение для передачи.
Возвращаемое значение
Количество записанных байт (считывать это значение необязательно).
Пример
#include <SoftwareSerial.h>
// Создаём новый объект SoftwareSerial: RX на цифровом пине 10, TX на цифровом пине 11
SoftwareSerial mySerial(10, 11);
void setup() {
// Устанавливаем скорость передачи для объекта SerialSoftware
mySerial.begin(9600);
}
void loop() {
// Отправляем байт со значением 45
mySerial.write(45);
//Отправляем строку «hello» и возвращаем её длину.
int bytesSent = mySerial.write(“hello”);
}
См. также
SoftwareSerial() available() begin() isListening() overflow() peek() read() print() println() listen()