Модуль Bluetooth HC-05 возвращает закодированные данные

Я искал в Интернете и не нашел никого, кто столкнулся бы с этой проблемой. Как ни странно, мой Bluetooth HC-05 возвращает закодированные данные. Я пробовал использовать разные платы - Induing, Uno, Freeduino, и у меня со всеми одна и та же проблема.

Я использую модуль Bluetooth модуль Bluetooth HC-05.

Когда я передаю команду «AT», я ожидаю, что ответ будет «ОК». Я получаю данные как

CF  A7  86  85

Это 8-битные данные, и если я уберу старший бит, я буду:

4F  27  06  05

Вместо этого я должен был получить:

4F  4B  0D  0A

Я посмотрел на двоичный шаблон, чтобы понять, похоже ли это на 7-битное кодирование, используемое в GSM.

Actual Data
CF       A7       86       85
11001111 10100111 10000110 10000101

Expected Data
4F  4B  0D  0A
01001111 01001011 00001101 00001010

Я попробовал другие AT-команды, и оказалось, что все закодировано.

Код, который я написал, довольно стандартный, модуль мигает импульсом 2 секунды (в командном режиме). Я получаю закодированный вывод для всех AT-команд. Я даже пробовал ORGL, INIT и другие команды, предложенные в различных дискуссионных темах.

#include <SoftwareSerial.h>

SoftwareSerial BtDongle = SoftwareSerial(10, 11);

void setup() {
  digitalWrite(9, LOW);
  delay(100);
  digitalWrite(9, HIGH);
  delay(100);  
  Serial.begin(9600);
  Serial.write("AT Command: \n\n");
  BtDongle.begin(38400); 
}

void loop() {
  while(BtDongle.available()) {
    unsigned char data = BtDongle.read();
    Serial.println(data, HEX);
  }

  while(Serial.available()) {
    char data = Serial.read();
    Serial.print(data);
    BtDongle.print(data);
  }    
}

, 👍5

Обсуждение

Похоже на проблему конфигурации последовательного интерфейса: попробуйте поиграться с количеством стоп-битов и четностью; есть, вероятно, одна комбинация, которая будет работать., @jfpoilpret

Я пробовал различные комбинации с Putty вместо встроенного в Arduino IDE Serial Monitor. Здесь выход не остановится! CFA78685CFA78685CFA78685CFA78685CFA78685CFA78685CFA78685... Во встроенном последовательном мониторе Шестнадцатеричный: В CFA78685 НА+ИМЯ? АБА6А0А629275469D62482C6C1B5416D5A60B18585CFA78685 АТ+версия? C5AAA9A7A94D4A4C4A23E1 СИМВОЛ: В Я§†… НА+ИМЯ? «¦ ¦Q'Ui…$‚ÆÁµÁmZ±……ϧ†… АТ+ВЕРСИЯ? «ª¢©*Õʦ'ºÁµIab°š˜˜Cáϧ†…, @Achindra Bhatnagar

Что ж, я столкнулся с подобной проблемой с модулем Wi-Fi RN 171. Ниже приведены несколько советов, которые я хотел бы, чтобы вы проверили., @Damon

Пожалуйста, поделитесь советами, которые я могу проверить?, @Achindra Bhatnagar

Кажется, некоторые биты теряются. Пожалуйста, добавьте буфер как для ввода, так и для вывода и начните передачу обратно на ПК только после того, как вы получите все от BT., @Avamander


3 ответа


1

Используйте осциллограф для проверки уровней на TX модуля BT. Некоторые модули HC-xx поставляются с уровнями 3,3 В, что может вызвать проблемы.

Я бы предложил использовать одинаковую скорость для последовательного порта и для ключа bt. У вас тут глюк, из-за которого могут возникнуть проблемы:

while(BtDongle.available()) {
  unsigned char data = BtDongle.read();
  Serial.println(data, HEX);
}

В конце концов, модуль Bluetooth отправляет вам данные с высокой скоростью передачи данных. Вы получаете первое письмо, а затем отправляете его на ПК с более низким битрейтом. Отправка его на ПК занимает столько времени, сколько ключ BT отправляет еще четыре символа.

Хотя в Arduino есть последовательные буферы, эта проблема легко может привести к потере данных, как указал @Avamander.

Основываясь на вашем комментарии о том, что вы смогли получить бесконечный беспорядок от Putty, это может привести к потере синхронизации на RX от модуля BT, а затем дальнейшие биты начнут новый байт, что приведет к полному беспорядку. . Однако OK должен работать, так что у вас, вероятно, тоже проблемы с уровнем.

,

2

У меня тоже возникла та же проблема, и после нескольких исследований я обнаружил, что она связана с ошибкой внутри библиотеки SoftwareSerial. Вот как это исправить:

  • Загрузите два файла новой версии библиотеки на гитхабе
  • Переименуйте их в mySoftwareSerial.cpp и mySoftwareSerial.h и поместите в рабочую папку
  • Заменить в рабочем файле и в файле mySoftwareSerial.h строку #include <SoftwareSerial.h> на

    #include "mySoftwareSerial.h"

  • Скомпилируйте и отправьте на Arduino. Он должен работать ! (Протестировано в режиме AT со скоростью 38 400 бод и в классическом режиме (режим +AT) со скоростью 57 600 бод на arduino nano)

Вы можете найти файл, который я использовал в конце сообщения.

Кстати, я также упомянул другую проблему, которая у меня возникла, которая не связана с этим, но может помочь: в некоторых моделях HC-05 у вас есть контакт EN вместо KEY. Здесь вместо подключения VCC к контакту KEY вам нужно нажать кнопку в верхней части платы HC-05 перед запуском модуля HC-05: эта кнопка подключит VCC к контакту 34 для вас. Но учтите, что если вы не будете удерживать эту кнопку нажатой, вы сможете выполнять только часть команд (например, AT+NAME? не будет работать, а AT+NAME=... и AT будут). Вы можете найти много дополнительной информации здесь.

Файлы, которые я использовал

Этот файл представляет собой «файл проекта», используемый для перенаправления классического последовательного соединения (Ctrl+Shift+M в программном обеспечении arduino) на устройство Bluetooth. Введите здесь команды AT.

#include "mySoftwareSerial.h"
SoftwareSerial BTserial(7, 8); // Прием | Передача
// Подключите HC-05 TX к контакту 2 RX Arduino.
// Подключите HC-05 RX к контакту 3 Arduino TX через делитель напряжения.
//

char c = ' ';

void setup() 
{
    Serial.begin(9600);
    Serial.println("Arduino is ready");
    Serial.println("Remember to select Both NL & CR in the serial monitor");

    // HC-05 последовательная скорость по умолчанию для режима AT 38400
    BTserial.begin(38400);
}

void loop()
{

    // Продолжаем читать с HC-05 и отправляем в Arduino Serial Monitor
    if (BTserial.available())
    {  
        c = BTserial.read();
        Serial.write(c);
    }

    // Продолжаем читать с последовательного монитора Arduino и отправляем на HC-05
    if (Serial.available())
    {
        c =  Serial.read();
        BTserial.write(c);  
    }

}

Файл mySoftwareSerial.h, взятый со страницы github:

/*
SoftwareSerial.h (ранее NewSoftSerial.h) —
Многоэкземплярная программная последовательная библиотека для Arduino/Wiring
-- Прием, управляемый прерываниями, и другие улучшения от ladyada
(http://ladyada.net)
-- Настройка, кольцевой буфер, производный от класса Print/Stream,
поддержка нескольких экземпляров, портирование на процессоры 8 МГц,
различные оптимизации, таблицы задержки PROGMEM, инверсная логика и
прямой порт написан Микалом Хартом (http://www.arduiniana.org)
-- Макросы прерывания смены контакта от Paul Stoffregen (http://www.pjrc.com)
-- Поддержка процессора 20 МГц компанией Garrett Mace (http://www.macetech.com)
-- Поддержка ATmega1280/2560 Бреттом Хагманом (http://www.roguerobotics.com/)
Эта библиотека является бесплатным программным обеспечением; вы можете распространять его и/или
изменить его в соответствии с условиями GNU Lesser General Public
Лицензия, опубликованная Free Software Foundation; или
версия 2.1 Лицензии или (по вашему выбору) любая более поздняя версия.
Эта библиотека распространяется в надежде, что она будет полезна,
но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ; даже без подразумеваемой гарантии
КОММЕРЧЕСКАЯ ПРИГОДНОСТЬ или ПРИГОДНОСТЬ ДЛЯ ОПРЕДЕЛЕННОЙ ЦЕЛИ. См. ГНУ
Меньшая стандартная общественная лицензия для более подробной информации.
Вы должны были получить копию GNU Lesser General Public
Лицензия вместе с этой библиотекой; если нет, напишите в Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Последнюю версию этой библиотеки всегда можно найти по адресу
http://arduiniana.org.
*/

#ifndef SoftwareSerial_h
#define SoftwareSerial_h

#include <inttypes.h>
#include <Stream.h>

/******************************************************************************
* Definitions
******************************************************************************/

#ifndef _SS_MAX_RX_BUFF
#define _SS_MAX_RX_BUFF 64 // Размер буфера RX
#endif

#ifndef GCC_VERSION
#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#endif

class SoftwareSerial : public Stream
{
private:
  // для данных объекта
  uint8_t _receivePin;
  uint8_t _receiveBitMask;
  volatile uint8_t *_receivePortRegister;
  uint8_t _transmitBitMask;
  volatile uint8_t *_transmitPortRegister;
  volatile uint8_t *_pcint_maskreg;
  uint8_t _pcint_maskvalue;

  // Выражается как задержка в 4 цикла (никогда не должна быть равна 0!)
  uint16_t _rx_delay_centering;
  uint16_t _rx_delay_intrabit;
  uint16_t _rx_delay_stopbit;
  uint16_t _tx_delay;

  uint16_t _buffer_overflow:1;
  uint16_t _inverse_logic:1;

  // статические данные
  static uint8_t _receive_buffer[_SS_MAX_RX_BUFF]; 
  static volatile uint8_t _receive_buffer_tail;
  static volatile uint8_t _receive_buffer_head;
  static SoftwareSerial *active_object;

  // приватные методы
  inline void recv() __attribute__((__always_inline__));
  uint8_t rx_pin_read();
  void setTX(uint8_t transmitPin);
  void setRX(uint8_t receivePin);
  inline void setRxIntMsk(bool enable) __attribute__((__always_inline__));

  // Возвращаем num-sub или 1, если результатом будет < 1
  static uint16_t subtract_cap(uint16_t num, uint16_t sub);

  // закрытый статический метод для определения времени
  static inline void tunedDelay(uint16_t delay);

public:
  // общедоступные методы
  SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic = false);
  ~SoftwareSerial();
  void begin(long speed);
  bool listen();
  void end();
  bool isListening() { return this == active_object; }
  bool stopListening();
  bool overflow() { bool ret = _buffer_overflow; if (ret) _buffer_overflow = false; return ret; }
  int peek();

  virtual size_t write(uint8_t byte);
  virtual int read();
  virtual int available();
  virtual void flush();
  operator bool() { return true; }

  using Print::write;

  // открытый только для легкого доступа обработчиками прерываний
  static inline void handle_interrupt() __attribute__((__always_inline__));
};

// Обходной путь Arduino 0012
#undef int
#undef char
#undef long
#undef byte
#undef float
#undef abs
#undef round

#endif

Файл mySoftwareSerial.cpp, также взятый со страницы github:

/*
SoftwareSerial.cpp (ранее NewSoftSerial.cpp) —
Многоэкземплярная программная последовательная библиотека для Arduino/Wiring
-- Прием, управляемый прерываниями, и другие улучшения от ladyada
(http://ladyada.net)
-- Настройка, кольцевой буфер, производный от класса Print/Stream,
поддержка нескольких экземпляров, портирование на процессоры 8 МГц,
различные оптимизации, таблицы задержки PROGMEM, инверсная логика и
прямой порт написан Микалом Хартом (http://www.arduiniana.org)
-- Макросы прерывания смены контакта от Paul Stoffregen (http://www.pjrc.com)
-- Поддержка процессора 20 МГц компанией Garrett Mace (http://www.macetech.com)
-- Поддержка ATmega1280/2560 Бреттом Хагманом (http://www.roguerobotics.com/)
Эта библиотека является бесплатным программным обеспечением; вы можете распространять его и/или
изменить его в соответствии с условиями GNU Lesser General Public
Лицензия, опубликованная Free Software Foundation; или
версия 2.1 Лицензии или (по вашему выбору) любая более поздняя версия.
Эта библиотека распространяется в надежде, что она будет полезна,
но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ; даже без подразумеваемой гарантии
КОММЕРЧЕСКАЯ ПРИГОДНОСТЬ или ПРИГОДНОСТЬ ДЛЯ ОПРЕДЕЛЕННОЙ ЦЕЛИ. См. ГНУ
Меньшая стандартная общественная лицензия для более подробной информации.
Вы должны были получить копию GNU Lesser General Public
Лицензия вместе с этой библиотекой; если нет, напишите в Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Последнюю версию этой библиотеки всегда можно найти по адресу
http://arduiniana.org.
*/


// Если установлено, _DEBUG использует выводы 11 и 13 для отладки с помощью
// осциллограф или логический анализатор. Осторожно: он также немного изменяет
// битовое время, так что не слишком полагайтесь на него при высоких скоростях передачи
#define _DEBUG 0
#define _DEBUG_PIN1 11
#define _DEBUG_PIN2 13
//
// Включает
//
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <Arduino.h>
#include "mySoftwareSerial.h"
#include <util/delay_basic.h>

//
// Статика
//
SoftwareSerial *SoftwareSerial::active_object = 0;
uint8_t SoftwareSerial::_receive_buffer[_SS_MAX_RX_BUFF]; 
volatile uint8_t SoftwareSerial::_receive_buffer_tail = 0;
volatile uint8_t SoftwareSerial::_receive_buffer_head = 0;

//
// Отладка
//
// Эта функция генерирует короткий импульс
// для отладки или измерения на осциллографе.
#if _DEBUG
inline void DebugPulse(uint8_t pin, uint8_t count)
{
  volatile uint8_t *pport = portOutputRegister(digitalPinToPort(pin));

  uint8_t val = *pport;
  while (count--)
  {
    *pport = val | digitalPinToBitMask(pin);
    *pport = val;
  }
}
#else
inline void DebugPulse(uint8_t, uint8_t) {}
#endif

//
// Приватные методы
//

/* static */ 
inline void SoftwareSerial::tunedDelay(uint16_t delay) { 
  _delay_loop_2(delay);
}

// Эта функция устанавливает текущий объект как "слушающий"
// один и возвращает true, если он заменяет другой
bool SoftwareSerial::listen()
{
  if (!_rx_delay_stopbit)
    return false;

  if (active_object != this)
  {
    if (active_object)
      active_object->stopListening();

    _buffer_overflow = false;
    _receive_buffer_head = _receive_buffer_tail = 0;
    active_object = this;

    setRxIntMsk(true);
    return true;
  }

  return false;
}

// Перестать слушать. Возвращает true, если мы действительно слушали.
bool SoftwareSerial::stopListening()
{
  if (active_object == this)
  {
    setRxIntMsk(false);
    active_object = NULL;
    return true;
  }
  return false;
}

//
// Процедура приема, вызываемая обработчиком прерывания
//
void SoftwareSerial::recv()
{

#if GCC_VERSION < 40302
// Обходной путь для ошибки версии avr-gcc 4.3.0 OSX
// Сохраняем регистры, которые пропускает компилятор
// (любезно предоставлено пользователем форума Arduino *etracer*)
  asm volatile(
    "push r18 \n\t"
    "push r19 \n\t"
    "push r20 \n\t"
    "push r21 \n\t"
    "push r22 \n\t"
    "push r23 \n\t"
    "push r26 \n\t"
    "push r27 \n\t"
    ::);
#endif  

  uint8_t d = 0;

  // Если линия RX имеет высокий уровень, то мы не видим никакого стартового бита
  // так что прерывание скорее всего не для нас
  if (_inverse_logic ? rx_pin_read() : !rx_pin_read())
  {
    // Запрещаем дальнейшие прерывания во время приема, это предотвращает
    // запуск другого прерывания сразу после возврата, что может
    // вызывают проблемы при более высоких скоростях передачи данных.
    setRxIntMsk(false);

    // Подождите примерно 1/2 битовой ширины, чтобы "отцентрировать" выборку
    tunedDelay(_rx_delay_centering);
    DebugPulse(_DEBUG_PIN2, 1);

    // Читаем каждый из 8 бит
    for (uint8_t i=8; i > 0; --i)
    {
      tunedDelay(_rx_delay_intrabit);
      d >>= 1;
      DebugPulse(_DEBUG_PIN2, 1);
      if (rx_pin_read())
        d |= 0x80;
    }

    if (_inverse_logic)
      d = ~d;

    // если буфер полон, установить флаг переполнения и вернуться
    uint8_t next = (_receive_buffer_tail + 1) % _SS_MAX_RX_BUFF;
    if (next != _receive_buffer_head)
    {
      // сохраняем новые данные в буфере: хвост указывает куда идет байт
      _receive_buffer[_receive_buffer_tail] = d; // сохранить новый байт
      _receive_buffer_tail = next;
    } 
    else 
    {
      DebugPulse(_DEBUG_PIN1, 1);
      _buffer_overflow = true;
    }

    // пропустить стоповый бит
    tunedDelay(_rx_delay_stopbit);
    DebugPulse(_DEBUG_PIN1, 1);

    // Повторно разрешаем прерывания, когда мы уверены, что находимся внутри стопового бита
    setRxIntMsk(true);

  }

#if GCC_VERSION < 40302
// Обходной путь для ошибки версии avr-gcc 4.3.0 OSX
// Восстанавливаем регистры, которые пропустил компилятор
  asm volatile(
    "pop r27 \n\t"
    "pop r26 \n\t"
    "pop r23 \n\t"
    "pop r22 \n\t"
    "pop r21 \n\t"
    "pop r20 \n\t"
    "pop r19 \n\t"
    "pop r18 \n\t"
    ::);
#endif
}

uint8_t SoftwareSerial::rx_pin_read()
{
  return *_receivePortRegister & _receiveBitMask;
}

//
// Обработка прерывания
//

/* static */
inline void SoftwareSerial::handle_interrupt()
{
  if (active_object)
  {
    active_object->recv();
  }
}

#if defined(PCINT0_vect)
ISR(PCINT0_vect)
{
  SoftwareSerial::handle_interrupt();
}
#endif

#if defined(PCINT1_vect)
ISR(PCINT1_vect, ISR_ALIASOF(PCINT0_vect));
#endif

#if defined(PCINT2_vect)
ISR(PCINT2_vect, ISR_ALIASOF(PCINT0_vect));
#endif

#if defined(PCINT3_vect)
ISR(PCINT3_vect, ISR_ALIASOF(PCINT0_vect));
#endif

//
// Конструктор
//
SoftwareSerial::SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic /* = false */) : 
  _rx_delay_centering(0),
  _rx_delay_intrabit(0),
  _rx_delay_stopbit(0),
  _tx_delay(0),
  _buffer_overflow(false),
  _inverse_logic(inverse_logic)
{
  setTX(transmitPin);
  setRX(receivePin);
}

//
// Деструктор
//
SoftwareSerial::~SoftwareSerial()
{
  end();
}

void SoftwareSerial::setTX(uint8_t tx)
{
  // Сначала запись, затем установка вывода. Если мы сделаем это наоборот,
  // на вывод будет выводиться низкий уровень в течение короткого времени перед переключением на
  // вывод высокий. Теперь он на короткое время вводится с подтягиванием, что
  // Это хорошо. С инверсной логикой любой порядок подходит.
  digitalWrite(tx, _inverse_logic ? LOW : HIGH);
  pinMode(tx, OUTPUT);
  _transmitBitMask = digitalPinToBitMask(tx);
  uint8_t port = digitalPinToPort(tx);
  _transmitPortRegister = portOutputRegister(port);
}

void SoftwareSerial::setRX(uint8_t rx)
{
  pinMode(rx, INPUT);
  if (!_inverse_logic)
    digitalWrite(rx, HIGH);  // подтягивание для нормальной логики!
  _receivePin = rx;
  _receiveBitMask = digitalPinToBitMask(rx);
  uint8_t port = digitalPinToPort(rx);
  _receivePortRegister = portInputRegister(port);
}

uint16_t SoftwareSerial::subtract_cap(uint16_t num, uint16_t sub) {
  if (num > sub)
    return num - sub;
  else
    return 1;
}

//
// Публичные методы
//

void SoftwareSerial::begin(long speed)
{
  _rx_delay_centering = _rx_delay_intrabit = _rx_delay_stopbit = _tx_delay = 0;

  // Предварительный расчет различных задержек в количестве 4-тактных задержек
  uint16_t bit_delay = (F_CPU / speed) / 4;

  // 12 (gcc 4.8.2) или 13 (gcc 4.3.2) циклов от начального бита до первого бита,
  // 15 (gcc 4.8.2) или 16 (gcc 4.3.2) циклов между битами,
  // 12 (gcc 4.8.2) или 14 (gcc 4.3.2) циклов от последнего бита до стопового бита
  // Все они достаточно близки, чтобы использовать всего 15 циклов, так как межбитовый
  // тайминги наиболее критичны (отклонения суммируются 8 раз)
  _tx_delay = subtract_cap(bit_delay, 15 / 4);

  // Настраиваем rx только тогда, когда у нас есть действительный PCINT для этого вывода
  if (digitalPinToPCICR(_receivePin)) {
    #if GCC_VERSION > 40800
    // Тайминги подсчитываются из вывода gcc 4.8.2. Это работает до 115200 на
    // 16 МГц и 57600 на 8 МГц.
    //
    // Когда появляется стартовый бит, есть 3 или 4 такта до
    // установлен флаг прерывания, за 4 такта до установки ПК вправо
    // адрес вектора прерывания и старый ПК помещается в стек,
    // и затем 75 циклов инструкций (включая RJMP в
    // Таблица векторов ISR) до первой задержки. После задержки там
    // еще 17 циклов, пока значение вывода не будет прочитано (исключая
    // задержка в цикле).
    // Нам нужна общая задержка в 1,5 бита. Внутри петли,
    // мы уже ждем 1 бит времени - 23 такта, так что здесь мы ждем
    // 0,5 битное время - (71 + 18 - 22) тактов.
    _rx_delay_centering = subtract_cap(bit_delay / 2, (4 + 4 + 75 + 17 - 23) / 4);

    // В каждой итерации цикла 23 такта (исключая задержку)
    _rx_delay_intrabit = subtract_cap(bit_delay, 23 / 4);

    // 37 циклов от последнего прочитанного бита до начала
    // задержка стоп-бита и 11 циклов от задержки до прерывания
    // маска снова включена (что _должно_ произойти во время стоп-бита).
    // Эта задержка составляет 3/4 бита времени, что означает конец
    // задержка будет равна 1/4 стопового бита. Это позволяет несколько доп.
    // время на очистку ISR, что заставляет работать больше 115200 бод на частоте 16 МГц
    // надежно
    _rx_delay_stopbit = subtract_cap(bit_delay * 3 / 4, (37 + 11) / 4);
    #else // Тайминги подсчитываются из вывода gcc 4.3.2
    // Обратите внимание, что этот код _много_ медленнее, в основном из-за плохого регистра
    // варианты размещения gcc. Это работает до 57600 на 16 МГц и
    // 38400 на 8МГц.
    _rx_delay_centering = subtract_cap(bit_delay / 2, (4 + 4 + 97 + 29 - 11) / 4);
    _rx_delay_intrabit = subtract_cap(bit_delay, 11 / 4);
    _rx_delay_stopbit = subtract_cap(bit_delay * 3 / 4, (44 + 17) / 4);
    #endif


    // Включите здесь PCINT для всего порта, но никогда не отключайте его
    // (это может понадобиться и другим, поэтому отключаем прерывание с помощью
    // регистр PCMSK для каждого контакта).
    *digitalPinToPCICR(_receivePin) |= _BV(digitalPinToPCICRbit(_receivePin));
    // Предварительно вычисляем регистр и значение маски pcint, поэтому setRxIntMask
    // можно использовать внутри ISR, не затрачивая слишком много времени.
    _pcint_maskreg = digitalPinToPCMSK(_receivePin);
    _pcint_maskvalue = _BV(digitalPinToPCMSKbit(_receivePin));

    tunedDelay(_tx_delay); // если мы были низкими, это устанавливает конец
  }

#if _DEBUG
  pinMode(_DEBUG_PIN1, OUTPUT);
  pinMode(_DEBUG_PIN2, OUTPUT);
#endif

  listen();
}

void SoftwareSerial::setRxIntMsk(bool enable)
{
    if (enable)
      *_pcint_maskreg |= _pcint_maskvalue;
    else
      *_pcint_maskreg &= ~_pcint_maskvalue;
}

void SoftwareSerial::end()
{
  stopListening();
}


// Чтение данных из буфера
int SoftwareSerial::read()
{
  if (!isListening())
    return -1;

  // Пустой буфер?
  if (_receive_buffer_head == _receive_buffer_tail)
    return -1;

  // Читаем из "головы"
  uint8_t d = _receive_buffer[_receive_buffer_head]; // захват следующего байта
  _receive_buffer_head = (_receive_buffer_head + 1) % _SS_MAX_RX_BUFF;
  return d;
}

int SoftwareSerial::available()
{
  if (!isListening())
    return 0;

  return (_receive_buffer_tail + _SS_MAX_RX_BUFF - _receive_buffer_head) % _SS_MAX_RX_BUFF;
}

size_t SoftwareSerial::write(uint8_t b)
{
  if (_tx_delay == 0) {
    setWriteError();
    return 0;
  }

  // Объявив их как локальные переменные, компилятор поместит их
  // в регистрах _перед_ отключением прерываний и вводом
  // критические временные разделы ниже, что значительно упрощает
  // проверяем время цикла
  volatile uint8_t *reg = _transmitPortRegister;
  uint8_t reg_mask = _transmitBitMask;
  uint8_t inv_mask = ~_transmitBitMask;
  uint8_t oldSREG = SREG;
  bool inv = _inverse_logic;
  uint16_t delay = _tx_delay;

  if (inv)
    b = ~b;

  cli();  // отключаем прерывания для чистого txmit

  // Записываем стартовый бит
  if (inv)
    *reg |= reg_mask;
  else
    *reg &= inv_mask;

  tunedDelay(delay);

  // Запись каждого из 8 бит
  for (uint8_t i = 8; i > 0; --i)
  {
    if (b & 1) // выбираем бит
      *reg |= reg_mask; // отправить 1
    else
      *reg &= inv_mask; // отправить 0

    tunedDelay(delay);
    b >>= 1;
  }

  // восстанавливаем контакт в естественное состояние
  if (inv)
    *reg &= inv_mask;
  else
    *reg |= reg_mask;

  SREG = oldSREG; // снова включить прерывания
  tunedDelay(_tx_delay);

  return 1;
}

void SoftwareSerial::flush()
{
  // Нет буферизации транзакций, просто возврат
}

int SoftwareSerial::peek()
{
  if (!isListening())
    return -1;

  // Пустой буфер?
  if (_receive_buffer_head == _receive_buffer_tail)
    return -1;

  // Читаем из "головы"
  return _receive_buffer[_receive_buffer_head];
}
,

0

Однажды у меня были проблемы с подключением последовательного кабеля GPS к Arduino. При подключении GPS к последовательному порту ПК COM1 все было в порядке. но arduino получал странные символы. Решение заключалось в том, чтобы установить для inverse_logic значение true, 3-й аргумент SoftwareSerial.

SoftwareSerial mySerial(10,11,true);

может быть, кто-то еще может объяснить, почему некоторые протоколы являются инверсными

,