Два сериала не могут работать на одной скорости

У меня есть устройство, которое подключается к контактам 10/11 платы Arduino UNO. Я пытаюсь отправлять команды с моего ПК с помощью Arduino для передачи моих команд на устройство через последовательный порт.

Проблема в том, что если я использую скорость 9600 как для устройства, так и для связи по USB, мои команды будут повреждены. Некоторые буквы заменяются странными символами и т.д. Устройство использует скорость 9600 бод.

Если я изменю скорость связи с ПК на 4800 (или любую скорость, кроме 9600), все будет в порядке. Но мне приходится использовать разные скорости для связи.

Мне не нравится обходной путь, потому что я не понимаю, что происходит. Может ли кто-нибудь объяснить, почему одинаковые скорости последовательного порта вызывают проблемы?

Вот мой код:

#include <SoftwareSerial.h>

#define rxPin 11
#define txPin 10

SoftwareSerial mySerial =  SoftwareSerial(rxPin, txPin);

 void setup()
 {
   digitalWrite(4,HIGH); // 1 - отключить
   mySerial.begin(9600);
   Serial.begin(19200);
   while (!Serial) {;}  // ждем подключения последовательного порта. Требуется только для родного порта USB
   Serial.println("Begin");
 }

 void loop()
 {
  if (mySerial.available()) 
  {
    char c = mySerial.read();
    Serial.write(c);  
  }
  if (Serial.available()) 
  {
    char c = Serial.read();
    mySerial.write(c); 
  }
 }

, 👍3

Обсуждение

SoftwareSerial не мой фаворит, и у меня не было хорошего вкуса с ним. Но, в любом случае, возможно, вы должны дать более подробную информацию об устройстве, которое вы подключаете к контактам 10 и 11., @Sener

@Sener Устройство представляет собой сервопривод RMCS 2201: Ссылка на спецификации Он имеет фиксированную скорость 9600 бод. Я подключил его напрямую к COM с помощью TTL-конвертера, и он отлично работает. Итак, я предполагаю, что где-то в моем коде есть проблема. Попробую ваш код буферизации. Спасибо ! Может подскажете чем заменить SoftwareSerial?, @Konstantin Borisov

Спасибо за подробную информацию об устройстве. Если он работает с модулем USB to TTL, то мы должны подумать о коде. Пожалуйста, попробуйте код, который я упомянул. И даже дальше, попробуйте вместо этого использовать аппаратный серийный номер., @Sener

Но Arduino Uno имеет только один аппаратный серийный номер с контактами 0: RX, 1: TX. Тогда вы не сможете использовать связь с ПК через USB. Вы также можете рассмотреть Arduino Mega с 4 последовательными портами., @Sener

Возможно прерывание от входящего байта что-то меняет в исходящем байте SoftwareSerial. Это возможно. Возможно, серводвигатель также имеет какой-то программный серийный номер и требует идеальной синхронизации последовательного сигнала. Чтобы избежать коллизий, вы можете сначала прочитать полную строку, как показывает ответ @Sener. Но вам лучше использовать аппаратный последовательный порт arduino mega или arduino leonardo., @Jot

Скорость серводвигателя может быть на несколько процентов выше или ниже. SoftwareSerial использует фиксированную скорость передачи данных, вы не можете это изменить. Аппаратный серийный номер вычисляет значение для регистра uart. Я думаю, что аппаратный серийный номер может установить немного другую скорость передачи данных., @Jot

@Jot, буферизованное чтение не помогло. Я заказал Мегу, чтобы решить эту проблему. Благодарю вас!, @Konstantin Borisov

@konstantin, можешь попробовать "понюхать" общение? Я имею в виду, когда связь продолжается, подключите провод RX USB TTL к контакту TX Arduino, затем к RX и проверьте, где связь повреждена., @frarugi87

Последовательное программное обеспечение работает только в полудуплексном режиме (вы не можете отправлять и получать одновременно). AltSoftSerial — очень хороший вариант. https://www.arduinolibraries.info/libraries/alt-soft-serial, @Dorian

Если вы используете UNO, то почему у вас есть эта строка: while (!Serial) {;}, которая даже в комментарии в вашем собственном коде говорит, что она не нужна для вашей платы?, @Delta_G


2 ответа


0

Если вы уверены, что устройство, которое вы подключили к Arduino Uno, имеет надежную прошивку для последовательной связи, вам может потребоваться некоторая буферизация перед ретрансляцией ваших команд;

#define RECORD_SIZE 100
void loop()
{
    RelayDataIfAvaliable();
}
void RelayDataIfAvaliable() {
    static char buffer[RECORD_SIZE];
    if (Serial.available())
    {
        if (readline(Serial.read(), buffer, RECORD_SIZE) > 0) {
            mySerial.write(buffer);
        }
    }
}
//Считывает все входящие данные в буфер один раз
int readline(int readch, char *buffer, int len)
{
    static int pos = 0;//Изначально было равно нулю. Но в нем отсутствовал первый символ!
    int rpos;
    //Serial.print(readch);
    if (readch > 0) {
        switch (readch) {
        case '\n': // Игнорировать новые строки
            break;
        case '\r': // Возврат по CR
            rpos = pos;
            pos = 0;  // Сбросить индекс позиции, готовый к следующему разу
            return rpos;
        default:
            if (pos < len - 1) {
                buffer[pos++] = readch;
                buffer[pos] = 0;
            }
        }
    }
    // Конец строки не найден, поэтому возвращаем -1.
    return -1;
}
,

Я играл с этим подходом. Буферизованное чтение не помогает. Та же проблема: все нормально, пока не выставлю одинаковую скорость для обоих сериалов. Заказал Мегаборд. Это должно решить проблему наверняка. :) Большое спасибо!, @Konstantin Borisov

Но есть еще один путь, прежде чем идти по этой дороге. Когда я проверил это техническое описание двигателя, он также может обмениваться данными через I2C или SPI. Вы бы тоже так не думали? Например, этот образец выглядит довольно многообещающе: [демонстрация RMC220x] (https://github.com/wincelet/tuftsrobotics_icc2015/blob/master/rmcs2203_demo), @Sener

Ах, еще одно, вы проголосовали против моего ответа (работа в процессе)? это было единственное место, где я мог разместить отформатированную кодировку, поэтому я не обязательно давал окончательный ответ. Я считаю, что по крайней мере это заслуживает уважения., @Sener

нет, это не мой голос против. Я отметил ваш ответ как полезный. Так как мне не хватает репутации, она записывается, но не отображается. Ваши ответы мне очень помогают!, @Konstantin Borisov

Спасибо за ваш отзыв и отметку моего ответа. Удачи с вашим проектом., @Sener


1

Я провел некоторое время, играя с вашим кодом, и кажется, что ваш код на самом деле зацикливает последовательный порт, поэтому, если они оба установлены на 9600 в качестве примера, и вы печатаете то, что отправляет другой, как в вашем коде, вы в конечном итоге в цикле, если вы хотите прочитать, что отправляет ваш последовательный порт, лучше поместить эти значения в переменную и отправить

если вы загрузите свой код, вы получите следующее сообщение в IDE arduino при попытке подключения к последовательному монитору:

Ошибка при открытии последовательного порта COM8. (Порт занят),

ваш порт занят, потому что один последовательный порт все время считывает данные с другого

Еще одна вещь, которую я бы использовал, если вы хотите повторить последовательный порт:

 
  if (mySerial.available()) 
  {
    //char c = mySerial.read();
    Serial.write(mySerial.read());  
  }

Надеюсь, это поможет вам

,