Serial Monitor speed question

Status
Not open for further replies.
Hello,

I have the following program running on an Arduino Mega 2560 that i'd like to move over to a Teensy. The problem I am having is that when I run it on the Teensy, it cuts the first digit off from the result and the response rate in the serial monitor changes to about once every second. As a side note, I know the teensy has the transmitterEnable() functionality and I was wondering if I could get help implementing that here instead of the preTransmission/postTransmission functions. Thanks in advance.

Code:
#include <ModbusMaster.h>

#define MAX485_DE 2 //Enable transmit pin for MAX485 (both RE/DE tied together)

// instantiate ModbusMaster object
ModbusMaster node;

void preTransmission()
{
  digitalWrite(MAX485_DE, 1);
}

void postTransmission()
{
  digitalWrite(MAX485_DE, 0);
}

void setup()
{
  pinMode(MAX485_DE, OUTPUT);

  digitalWrite(MAX485_DE, 0);

  // Baudrate for serial monitor if you want to see responses
  while (!Serial);
  Serial.begin(38400);

  //Baudrate of modbus device is 38400
  while (!Serial1);
  Serial1.begin(38400);

  // Modbus slave ID is 9 and MAX485 is connected to RX1/TX1
  node.begin(9, Serial1);
  // Callbacks allow us to configure the RS485 transceiver correctly
  node.preTransmission(preTransmission);
  node.postTransmission(postTransmission);
}

void loop()
{
  uint8_t result;
  //Need data from starting address 0x41 with length 2
  result = node.readHoldingRegisters(0x41, 2);

  Serial.println(node.getResponseBuffer(0x00) / 10.00);

}
 
Not mentioned which Teensy #.#?

Problem is likely the Teensy is so fast it saturates the USB line faster than the Serial Monitor can hope to display.

Replace loop() with this::
Code:
void loop()
{
  static uint32_t lCnt=0;
  uint8_t result;
  ++lCnt;
  if ( !(lCnt%1000) ) {
    //Need data from starting address 0x41 with length 2
    result = node.readHoldingRegisters(0x41, 2);
    Serial.print( micros());
    Serial.print("\t");
    Serial.println(node.getResponseBuffer(0x00) / 10.00);
  }

}

The above code should give an idea of how much faster taking the difference between the appearance of the micros() value. Run it on the Mega and the Teensy

That might also slow it down enough on the Teensy to show valid info on SerMon.

For a better solution perhaps limit the output to a reasonable rate, or only when the value changes.
 
it cuts the first digit off from the result and the response rate in the serial monitor changes to about once every second.

Only once per second is incredibly slow!

I tried coping your code into Arduino to see if I could do anything to reproduce the problem, but it seems your code in msg #1 isn't a complete program I can actually compile and run.

screenshot.png
 
Ah, ok. Got the library installed.

Running it with no hardware connected indeed is slow. Looks like it's waiting 2 seconds, due to this line in ModbusMaster.h.

Code:
    // Modbus timeout [milliseconds]
    static const uint16_t ku16MBResponseTimeout          = 2000; ///< Modbus timeout [milliseconds]

I edited this to 100, and indeed it prints 0.00 much faster!
 
While I don't have a modbus device here, I did connect my oscilloscope. Here's the waveforms I see on pins 1 and 2.

file1.png

I tried changing the code to use the automatic DE pin support in Serial1 rather than the callbacks.

Code:
#include <ModbusMaster.h>

#define MAX485_DE 2 //Enable transmit pin for MAX485 (both RE/DE tied together)

// instantiate ModbusMaster object
ModbusMaster node;

void setup()
{
  pinMode(MAX485_DE, OUTPUT);
  digitalWrite(MAX485_DE, 0);

  // Baudrate for serial monitor if you want to see responses
  while (!Serial);
  Serial.begin(38400);

  //Baudrate of modbus device is 38400
  while (!Serial1);
  Serial1.begin(38400);
  Serial1.transmitterEnable(MAX485_DE);

  // Modbus slave ID is 9 and MAX485 is connected to RX1/TX1
  node.begin(9, Serial1);
}

void loop()
{
  uint8_t result;
  //Need data from starting address 0x41 with length 2
  result = node.readHoldingRegisters(0x41, 2);

  Serial.println(node.getResponseBuffer(0x00) / 10.00);

}

Looks like pretty much the same result.

file2.png
 
While I don't have a modbus device here, I did connect my oscilloscope. Here's the waveforms I see on pins 1 and 2.

View attachment 25429

I tried changing the code to use the automatic DE pin support in Serial1 rather than the callbacks.

Code:
#include <ModbusMaster.h>

#define MAX485_DE 2 //Enable transmit pin for MAX485 (both RE/DE tied together)

// instantiate ModbusMaster object
ModbusMaster node;

void setup()
{
  pinMode(MAX485_DE, OUTPUT);
  digitalWrite(MAX485_DE, 0);

  // Baudrate for serial monitor if you want to see responses
  while (!Serial);
  Serial.begin(38400);

  //Baudrate of modbus device is 38400
  while (!Serial1);
  Serial1.begin(38400);
  Serial1.transmitterEnable(MAX485_DE);

  // Modbus slave ID is 9 and MAX485 is connected to RX1/TX1
  node.begin(9, Serial1);
}

void loop()
{
  uint8_t result;
  //Need data from starting address 0x41 with length 2
  result = node.readHoldingRegisters(0x41, 2);

  Serial.println(node.getResponseBuffer(0x00) / 10.00);

}

Looks like pretty much the same result.

View attachment 25430


Thank you for digging into this. I played around with it a little more and plugged into my oscilloscope with the Arduino and then the Teensy and compared the two graphs and they look the same. I then changed from the callbacks for the transmit enable pin to what you have using 'Serial1.transmitterEnable' and now I get the correct numbers in the serial monitor and it's very quick as i'd expect.

I believe that time-out applies to when the modbus request doesn't get a response? That being the case, what would using the transmitterEnable function change about this?
 
Letting the serial driver code control DE gives probably accurate timing.

If the transmitter turns off too soon, it could cause the outgoing message to be truncated slightly and maybe the other device hears an invalid message (or detects noise or disruption during the stop bit) and doesn't reply? Or if it turns off too late, maybe the transmitter might still be enabled just as the other device starts to reply? If the beginning of the incoming stop bit is cut off, the entire incoming message could be received wrong because the UART paces where it will sample each bit based on timing from the falling edge of the start bit.

Most well designed half duplex devices use a "turnaround delay", where slave / sensor devices pauses for a brief time before transmitting a reply, and the master / controller waits a brief time before transmitting another request. 1 ms is a typical delay, at least in RS485 devices I've used in the distant past. Devices with little or no turnaround delay communicate slightly faster, but it's risky if the timing changes slightly.
 
Okay so I'm back at it and I found something that I don't quite understand. First, it stopped broadcasting new data and I didn't change anything. So I started playing around with the wires to see if something was up there. When I unplug the GND from the MAX485 board, everything works. Which doesn't make sense because there isn't another ground on the board. So by process of elimination I started checking what else would be acting as a ground as the LED on the max485 chip stays lit when the actual ground is disconnected. Turns out the transmitterEnable wire is the culprit which is just plugged into PIN 2 on the Teensy.

Any idea what would be going on there?
 
Status
Not open for further replies.
Back
Top