packetSerial library question

hi there, I’m trying to send requests from a master (Mega) to two slaves (Uno) using the packetSerial library. all three Arduinos are on the same TX/RX bus.

the master sends first a request ‘A’ and then two seconds later ‘B’, the idea is that the slaves respond with the right identifier and number.

When I have only one of the Unos connected, it works, however, as soon as I connect both I only get ‘B’ to reply; I cannot figure out what’s going on, can anyone advise? this is my first time trying this sort of thing and I am not sure how to go about figuring out why it won’t work.

Code master:

#include <PacketSerial.h>

PacketSerial masterPacketSerial; // initialize the packetserial object

byte identifier1 = 'A';   // ID of the first SLAVE Arduino we want to request
byte identifier2 = 'B';   // ID of the secoond SLAVE Arduino we want to request
int message = 0;         // received integer

void setup() {
  Serial.begin(9600);     // Debug output
  Serial1.begin(9600);    // Hardware serial link to the SLAVE

  // Setup PacketSerial on Serial1
  masterPacketSerial.setStream(&Serial1); // set serial one as the packetserial stream
  masterPacketSerial.setPacketHandler(&onPacketReceived);
}

void loop() {

  // Update PacketSerial to look for packets
  masterPacketSerial.update(); // contiuously look for updates

  // --- Send request to slave 01 ---
  uint8_t requestPacket1[1] = { identifier1 }; // create array: a message to send (in this case our identifier)
  masterPacketSerial.send(requestPacket1, 1); // send the array "requestpacket", the size is "1"
  Serial.println("sentID: A");

  unsigned long startTime = millis();
  while (millis() - startTime < 100) {
    masterPacketSerial.update();
  }

  delay(2000);   // Next request in 2 seconds

   // --- Send request to slave 01 ---
  uint8_t requestPacket2[1] = { identifier2 }; // create array: a message to send (in this case our identifier)
  masterPacketSerial.send(requestPacket2, 1); // send the array "requestpacket", the size is "1"
  Serial.println("sentID: B");

  startTime = millis();
  while (millis() - startTime < 100) {
    masterPacketSerial.update();
  }

  delay(2000);   // Next request in 2 seconds
}


// Called when a complete packet from the SLAVE arrives
void onPacketReceived(const uint8_t* buffer, size_t size) {

  // Expect exactly 3 bytes (int16)
  if (size != 3) {
    Serial.println("Invalid packet size");
    return;
  }

  char ident = buffer[0];
  byte highB = buffer[1]; // save into byte the first byte of buffer
  byte lowB  = buffer[2]; // save into byte the second byte of buffer

  message = (highB << 8) | lowB;  // reconstruct int16

  // Debug print
  Serial.print("Received Identifier: ");
  Serial.println(ident);
  Serial.print("Received: ");
  Serial.println(message);
//  Serial.print("Binary: ");
//  Serial.println(message, BIN);
}

Code slave (this is ‘B’ now – ‘A’ has the same code but a different identifier and dataToSend1):

#include <PacketSerial.h>

PacketSerial myPacketSerial;

byte identifier1 = 'B';        // This Arduino's ID
float dataToSend1 = 22222.54;  // Your data (could be load cell reading)

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

  // Setup PacketSerial
  myPacketSerial.setStream(&Serial);
  myPacketSerial.setPacketHandler(&onPacketReceived);
}

void loop() {
  // Update PacketSerial to check for incoming packets
  myPacketSerial.update();

  // You can update dataToSend here if needed
  // dataToSend = readLoadCell(); // example
}

// This function is automatically called when a complete packet arrives
void onPacketReceived(const uint8_t* buffer, size_t size) {
  // Check if we received at least 1 byte
  if (size < 1) return;

  char request = buffer[0];
  //Serial.println(request);

  // If the request matches our identifier, send data
  if (request == identifier1) {
    int dataInt = (int)dataToSend1;  // convert float to int by chopping off the .54

    // Prepare response packet with 2 bytes
    uint8_t response[3];
    response[0] = identifier1;
    response[1] = highByte(dataInt);
    response[2] = lowByte(dataInt);

    // Send the packet
    myPacketSerial.send(response, 3);
  }
}

The mega has 3 UARTs. Why not use #1 for USB serial to PC, #2 for talking to one Uno, and #3 for talking to the other Uno? It’s okay to have > 1 RX line connected to one TX line. I don’t think it’s going to work if you have > 1 TX line connected together because the two or more Tx outputs will be trying to output different logic levels, unless you have some way of avoiding that conflict

thanks for replying to this.

background: this is a dry run for something that later should include 6 nanos as slaves. so I am trying to just get basic communication on one bus to work.

not sure I am following your point about the logic levels. could you explain?

I’ve read smth somewhere else about using diodes and pullups when connecting multiple Arduinos to the same TX/RX bus but not sure I understand the issue.

I’m assuming your serial wiring is like this:

The ‘From Tx on mega’ is okay and should work, because you have one output driving two inputs. The ‘To Rx on mega’ is the problem. As I see it you have two output pins (Nano 1 pin 1 and Nano 2 pin 1) connected together. What logic level would the mega see if Nano 1 output was logic 1 and Nano 2 output was logic 0? This is probably why it works when you only connect 1 Uno.

I’ve not tried doing that. I don’t know how it could work in this case. Someone else reading this may know how to do that.

How long do the wires need to be between the Mega and the Nanos? Perhaps I2C would be a better option. The Nanos would be I2C slaves and the Mega would be the master. I2C is designed to have one master and multiple slaves

yeah, your assumption is correct, the wiring is like that.

I see. so one Uno is driving up and the other one down, is that what you are saying? still strange that I am getting ‘B’ very clearly but not ‘A’.

In the end, I’d need about a 4m cable to the last Nano and one Nano every 60cm or so between, so I think I2C is not an option. I’ve bought MAX485 modules but wanted to test the ‘simplest’ setup first.

@gabechan

You might want to have a look at RS485 modules.
These allows to connect multiple slaves to one serial bus.
As bonus these allow long distance communication.

Yes that’s what I’m saying. IDK why it would work in some cases. Without checking in a lot of detail, IDK off the top of my head what level would be seen by the receiver when one output is a logic 1 and the other is a logic 0. There’s also the possibility of damaging an output by doing this.

And have the risk of damaging Nanos in the process? An idle Tx pin has a 5V output level. Connecting a second Tx that is idle is already not the best idea (both will more than likely not be at exactly the same voltage) but it gets worse if one of them starts sending data and hence the output goes low (GND) when a serial bit is 0; that will result in a short.

It's a hack and can be made to work.

It relies on the resting condition of TTL serial being HIGH.

Wire a pull-up of 10K to the RX input.

Connect both TX outputs to that pulled-up RX input, each through a diode with the cathode side towards its respective TX output.

Either TX output can then pull down the RX input. Obvsly here and in any case your protocol should guarantee that the two transmitters cooperate. Take turns, whatecer.

It has issues. One, the voltage drop across those diodes, can be minimised by using Schottky diodes.

It can make higher speeds more problematic.

You could use multiple inputs on the master side, either half a real UART or SoftwareSerial.

But RS485 is what this is for.

a7

thanks for everyone’s replies. I think I’ll get my self some RS-485 modules first thing in the morning. :relieved_face:

1 Like