Невозможно заменить SoftwareSerial на Serial1 на плате Mega.

Этот эскиз хорошо работает с определением SoftwareSerial, и на мониторе отображаются значения Modbus устройства. Но теперь я хочу заменить SoftwareSerial на Serial1. и у меня нет данных.

Это скетч с SoftwareSerial:

#include <SoftwareSerial.h>
#define SSerialRX        10  //Пин последовательного приема
#define SSerialTX        11  //Вывод последовательной передачи
#define SSerialTxControl 40   // Управление направлением RS485
#define RS485Transmit    HIGH
#define RS485Receive     LOW


SoftwareSerial RS485Serial(SSerialRX, SSerialTX); // прием, Техас
byte byteSend;


void setup()   
{
  Serial.begin(9600);
  pinMode(SSerialTxControl, OUTPUT);  
  digitalWrite(SSerialTxControl, RS485Transmit);  // Инициализация трансивера
  RS485Serial.begin(9600);   
}
void loop()   
{
  delay(500);
  if (RS485Serial.available()) 
  { for(int i=0; i<7; i++)
    {
    byteSend = RS485Serial.read();   // Читаем байт

    Serial.print(byteSend, HEX);
    Serial.print(" ");
    }
  }
  digitalWrite(SSerialTxControl, RS485Transmit);  // Инициализация трансивера
  byte request[] = {0x01, 0x03, 0x00, 0x00, 0x00, 0x01, 0x84, 0x0A}; 
  RS485Serial.write(request, sizeof(request));

  digitalWrite(SSerialTxControl, RS485Receive);
  Serial.println(" ");
}

И эскиз, который я пробовал с Serial1 (контакты 19(Rx) и 18(Tx)):

#define SSerialTxControl 40   //Управление направлением RS485
#define RS485Transmit    HIGH
#define RS485Receive     LOW

byte byteSend;


void setup()   
{
  Serial.begin(9600);
  pinMode(SSerialTxControl, OUTPUT);  
  digitalWrite(SSerialTxControl, RS485Transmit);  // Инициализация трансивера
  Serial1.begin(9600);   
}
void loop()   
{
  delay(500);
  if (Serial1.available()) 
  { for(int i=0; i<7; i++)
    {
    byteSend = Serial1.read();   // Читаем байт

    Serial.print(byteSend, HEX);
    Serial.print(" ");
    }
  }
  digitalWrite(SSerialTxControl, RS485Transmit);  // Инициализация трансивера
  byte request[] = {0x01, 0x03, 0x00, 0x00, 0x00, 0x01, 0x84, 0x0A}; 
  Serial1.write(request, sizeof(request));

  digitalWrite(SSerialTxControl, RS485Receive);
  Serial.println(" ");
}

Можете ли вы помочь мне найти мою ошибку?

, 👍1

Обсуждение

ваш код ожидает 7 байт после запроса, доступен ли хотя бы один, @Juraj

https://majko.co.uk/blog/reading-serial-arduino, @Majenko

Извините, но я не понимаю, что вы имеете в виду? Есть ли разница в длине byteSend при использовании SoftwareSerial или Serial1?, @Teddol

Разница, вероятно, связана с тем, что SoftwareSerial::read() занимает полное время символа (около 105 мксек при скорости 9600 бод), поскольку отдельные биты собираются программным обеспечением. При использовании аппаратного UART вызов ::read() занимает всего несколько микросекунд, поскольку биты собираются аппаратно, без задержки программного обеспечения (много...). Таким образом, в аппаратном случае цикл() может выполнять вызов ::read() гораздо чаще, чем могут поступать символы. Короткий ответ: в программной версии вам просто повезло!, @JRobert

Так как же лучше всего решить эту проблему, используя Serial1?, @Teddol

Я пробовал советы Маженко, но на мониторе ничего не было..., @Teddol

Вам нужно дождаться, пока все будет передано, прежде чем отключать управляющий сигнал. Попробуйте добавить Serial1.flush() https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/HardwareSerial.cpp#L205. При поиске на github.com библиотек arduino rs485 каждая библиотека, которую я может найти использование Serial.flush или задержку, позволяющую передать байт перед понижением уровня управляющего сигнала., @Jot

Хорошо, я попытаюсь., @Teddol


1 ответ


2

Как лучше всего решить эту проблему, используя Serial1?

При использовании любого последовательного устройства вам необходимо собирать символы, пока не получите полное сообщение. Если каждое сообщение будет иметь фиксированное количество байтов, вы можете подождать, пока возвращаемое значение вызова Serial::available() не укажет, что оно содержит необходимое количество символов, а затем собрать их в буфер и обработать. Но это предполагает, что вы никогда не получите неправильно сформированное сообщение. Если вы это сделаете, входящие байты не будут синхронизированы с вашей программой. Лучший способ — собирать байты в буфер (но ничего с ними не делать) до тех пор, пока вы не получите полное сообщение (по количеству байтов, символу новой строки или как-то еще, когда вам нужно признать, что оно завершено) или пока ваш буфер не переполнится. , а затем либо обработайте их, либо, если ваш буфер заполнен и содержимое не выглядит как допустимое сообщение, отбросьте его и попытайтесь повторно синхронизировать с источником. Это может означать чтение и игнорирование байтов до тех пор, пока вы не получите новую строку, и обработку факта, что вы получили искаженное сообщение, или указание вашему источнику перезапустить или сбросить настройки. Точный метод (или хотите ли вы вообще обнаружить плохие сообщения) зависит от конкретной ситуации. Кто-нибудь умрет, если вы потерпите неудачу? Может ли что-то загореться, сгореть детали, потерять ценные данные за несколько недель...? Или это эксперимент, последствия неудачи которого равны нулю или, по крайней мере, не стоят усилий по его обнаружению?

,