Странное поведение softwareserial

Тема в разделе "Arduino & Shields", создана пользователем cfif, 12 май 2023.

Метки:
  1. cfif

    cfif Нерд

    Камрады, столкнулся с такой проблемой. Подключаю 2 устройства по SoftwareSerial. Вот код:
    Код (C++):
    // TRANSMITTER
    #include <Arduino.h>
    #include <SoftwareSerial.h>

    SoftwareSerial serialHC06(9, 10); // RX, TX

    SoftwareSerial serialE32(11, 12); // RX, TX   E32_RX -> PIN_12 Nano, E32_TX -> PIN_11 Nano

    String buffer_string;

    void setup()
    {
      Serial.begin(9600);

      serialHC06.begin(9600);
      serialE32.begin(9600);

      Serial.setTimeout(50);
      serialHC06.setTimeout(50);
      serialE32.setTimeout(50);

      Serial.println("TRANSMITTER ready!");
    }

    void loop()
    {
      // Если есть данные в Serial
      if (Serial.available())
      {
        buffer_string = Serial.readString();

        // выводим в serial сообщение
        Serial.print("get message from Serial: " + buffer_string);
        serialHC06.print("get message from Serial: " + buffer_string);
      }

      // Если есть данные от блютуз
      if (serialHC06.available())
      {
        buffer_string = serialHC06.readString();

        // выводим в serial сообщение
        Serial.print("get message from serialHC06: " + buffer_string);
      }

      // Если есть данные по радио
      if (serialE32.available())
      {
        buffer_string = serialE32.readString();

        // выводим в serial сообщение
        Serial.print("get message from serialE32: " + buffer_string);
      }

    }
    Проблема следующая при передаче данных с этих устройств - с одного из них данные принимаются, а с другого нет. Причем по отдельности всё работает. Проблемы при совместной работе. С помощью научного тыка и такой-то матери выяснил проблемное место. Если я меняю местами строки
    Код (C++):
      serialHC06.begin(9600);
      serialE32.begin(9600);
    тогда то устройство, которое объявлено последним - работает нормально, а первое нет.
    Уточню: если serialE32.begin(9600); объявлено последним, то с него данные принимаются, а с
    serialHC06 - нет. И наоборот. Причем передача данных работает в обоих случаях.
    В чем может быть причина?
     
  2. cfif

    cfif Нерд

    Разобрался с этой проблемой(( поспешил тему создать.
    Эта библиотека при приеме данных использует прерывание. Это прерывание только одно. Значит одновременно принимать два порта не могут.
     
  3. Ariadna-on-Line

    Ariadna-on-Line Гуру

    Скорее всего
    serialNNNN.begin(9600)
    использует какой-то общий ресурс, типа прерывания, и приписывает его к тем или иным входным пинам. Он(оно) задействован только в процессе "ловли" входящих данных. Тут решение - либо искать более "умную" библиотеку SoftSerial-а, либо поочередно открывать-закрывать порты.
    ПС. Ну вот мы сошлись в мыслях.
     
    cfif нравится это.
  4. cfif

    cfif Нерд

    да, сейчас пытаюсь найти альтернативу SoftwareSerial. Пока что-то не очень получается(( Поочередное открытие и закрытие - не очень хочу делать - данные будут теряться. Ну или буду пробовать на HardwareSerial подключиться - что тоже пляски с бубнами будут((
     
  5. cfif

    cfif Нерд

    попытался настроить работу с библиотекой NeoSWSerial. Тоже 2 порта не работают(( по отдельности всё отлично. И совместно с SoftwareSerial не компилируется
     
  6. parovoZZ

    parovoZZ Гуру

    я бы свой программный сериал написал. Там нет ничего сложного.
     
  7. Airbus

    Airbus Радиохулиган Модератор

    Зачем?Сам же говорил что для этого надо поступить в ЛЭТИ на бюджет,отучиться и закончить с красным дипломом. Долго блин! Лучше готовую библиотеку.
     
  8. Ariadna-on-Line

    Ariadna-on-Line Гуру

    Без двух аппаратных Сериалов - ваша задача не решаема. Аппаратный сериал - это самостоятельный контроллер внутри процессора, независимый от его ядра. Он сам обрабатывает процесс, а ядру выдает готовые данные (когда оно потребует). А СофтСериал - это работает само ядро. Обработать два одновременно приходящих процесса - оно физически не может. Просто потому что возникает временнОй конфликт. Поэтому Паровоз гонит пургу.
     
  9. parovoZZ

    parovoZZ Гуру

    А долго ли его написать? Нужна пара программных таймеров и пара буферов ввода-вывода и всё. Два софтовых сериала готовы.
     
  10. cfif

    cfif Нерд

    на забугорном форуме нашел: What's really needed is the ability to check on multiple pins when an interrupt comes along from the start bit. Then you'd have to set up pointers to the appropriate data structures. It would be complicated, but possible.
    Немного не понял, про какие пины идет речь и про прерывание не совсем понял.
    Т.е. когда приходят данные по Serial вызывается прерывание и в этот момент нужно проверить значение порта какого-нибудь , который укажет на какой пин пришли данные? или это сообщение вообще не про это?
     
  11. cfif

    cfif Нерд

    всё, победил я его))) воспользовался библиотекой AltSoftSerial. Там только ограничение - нужно RX устройства присоединить на 9 пин на ардуино, а TX устройства на 8 пин на ардуино. Таким образом у меня сейчас так:
    Код (C++):
    #include<Arduino.h>
    #include<SoftwareSerial.h>
    #include<AltSoftSerial.h>

    AltSoftSerial serialHC06;
    SoftwareSerial serialE32(11, 12); // RX, TX   E32_RX -> PIN_12 Nano, E32_TX -> PIN_11 Nano
    по обоим устройствам данные передаются в обе стороны
     
  12. parovoZZ

    parovoZZ Гуру

    прерывание нужно для того старта приёма. Прием/передача начинается с прижатия линии к нулю на 2 (или 2.5 - не понмю точно) интервала передачи одного символа. После чего необходимо считать первый бит, через едининый интервал второй бит и так все восемь битов. Далее идёт бит чётности (при наличии) и стоп бит. Ничего сложного. Таким образом можно организовать хоть сколько софтовых сериалов. Пока ног хватит. А если не хватит, то сдвиговый регистр в помощь.
     
    cfif нравится это.
  13. Ariadna-on-Line

    Ariadna-on-Line Гуру

    Вероятно потому что это ВЫ проверяете каналы - ПО ОЧЕРЕДИ. Но когда два девайса самостоятельно и ОДНОВРЕМЕННО пошлют данные ? Данные одного из них (тот кто начал позднее) - потеряются.
    ПС. Однако спасибо за альтернативную библиотеку. Сохраню про запас, хоть по логике, ОДНОМОМЕНТНОЙ многоканальности она не даст. Натыкался когда-то на вашу проблему. Но большой нужды тогда не было решать загадку. Вышел из положения открыванием-закрыванием портов.
     
    Последнее редактирование: 13 май 2023
  14. parovoZZ

    parovoZZ Гуру

    ничего никуда не потеряется. Считывать значения PIN регистра со скоростью 9600 Гц для МК с тактовой частотой в 20 МГц - это как забег спринтера и черепахи.
     
  15. Ariadna-on-Line

    Ariadna-on-Line Гуру

    Вообще-то в СофтСериале есть функция выбора портов без их открытия-закрытия. Чето я про нее забыл. Может она нужна ТС-у.
    Вот же классика из примеров.
    Код (C++):
    /*
      Software serial multiple serial test

    Receives from the two software serial ports,
    sends to the hardware serial port.

    In order to listen on a software port, you call port.listen().
    When using two software serial ports, you have to switch ports
    by listen()ing on each one in turn. Pick a logical time to switch
    ports, like the end of an expected transmission, or when the
    buffer is empty. This example switches ports when there is nothing
    more to read from a port

    The circuit:
    Two devices which communicate serially are needed.
    * First serial device's TX attached to digital pin 10(RX), RX to pin 11(TX)
    * Second serial device's TX attached to digital pin 8(RX), RX to pin 9(TX)

    Note:
    Not all pins on the Mega and Mega 2560 support change interrupts,
    so only the following can be used for RX:
    10, 11, 12, 13, 50, 51, 52, 53, 62, 63, 64, 65, 66, 67, 68, 69

    Not all pins on the Leonardo support change interrupts,
    so only the following can be used for RX:
    8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI).

    created 18 Apr. 2011
    modified 19 March 2016
    by Tom Igoe
    based on Mikal Hart's twoPortRXExample

    This example code is in the public domain.

    */


    #include <SoftwareSerial.h>
    // software serial #1: RX = digital pin 10, TX = digital pin 11
    SoftwareSerial portOne(10, 11);

    // software serial #2: RX = digital pin 8, TX = digital pin 9
    // on the Mega, use other pins instead, since 8 and 9 don't work on the Mega
    SoftwareSerial portTwo(8, 9);

    void setup() {
      // Open serial communications and wait for port to open:
      Serial.begin(9600);
      while (!Serial) {
        ; // wait for serial port to connect. Needed for native USB port only
      }


      // Start each software serial port
      portOne.begin(9600);
      portTwo.begin(9600);
    }

    void loop() {
      // By default, the last initialized port is listening.
      // when you want to listen on a port, explicitly select it:
      portOne.listen();
      Serial.println("Data from port one:");
      // while there is data coming in, read it
      // and send to the hardware serial port:
      while (portOne.available() > 0) {
        char inByte = portOne.read();
        Serial.write(inByte);
      }

      // blank line to separate data from the two ports:
      Serial.println();

      // Now listen on the second port
      portTwo.listen();
      // while there is data coming in, read it
      // and send to the hardware serial port:
      Serial.println("Data from port two:");
      while (portTwo.available() > 0) {
        char inByte = portTwo.read();
        Serial.write(inByte);
      }

      // blank line to separate data from the two ports:
      Serial.println();
    }
     
    Последнее редактирование: 13 май 2023
    cfif нравится это.
  16. cfif

    cfif Нерд

    на этот пример я натыкался, когда искал решение. Но посчитал, что в этом случае пакеты от второго устройства могут потеряться, пока будет вестись прием от первого устройства