Binary Communication - Command Request Question

Hello all

I've been working on a project that involves communicating with an ECU. From the ECU, i have TX RX (and i suppose a GND and VO black and red wire- not sure about this, no info about it) connected to arduino Serial1 (MEGA pins 18 and 19). From the little information i've got regarding the operation of the ECU, i know that it understands binary data.
The commands and requests follow a very specific data frame. A command usually has about 12 chars {{D20202D6}}, for example.

I'm having lot of problems communicating with the ECU, since i cannot get a proper answer from it and I was wondering where did I went wrong.
I just want to understand how arduino writes in the serialPort. Been reading about all the possibilities but after so much time, I guess I'm confused and don't know what else to do.

I want to perform a really simple test.
To send a command {{D20202D6}} and to read the answer out of Serial port in the proper format. How should i proceed?

I've tried Serial.write('{') and send byte per byte and i do have an answer, but It should follow the same specifications regarding startframe and end frame ( "{{" and "}}"). Not sure if the equipment is not working properly, or if I am.

Thanks!

Code? Example Response?

You really need to know/supply more info on the ECU as there are several different serial protocols, speeds and voltages levels. Some voltage levels may/will damage your arduino if connected directly to pins.

I wished I had also. They hand this equipment over and not even the pinout im totally sure of. It consists on Green, Red Blue and Black wire. But yes, forgot to mention baudrate info:

9600, 8 data bits, one stop bit, no parity, TTL values

Regarding the code, i opted for not including, since I'm only trying to understand the basics of communication using binary data, and im not sure if my answers are making any sense, since they all seem random.

Took some more time to reply since I was trying to post in some codes and results. But each time i reset the arduino while checking the serial monitor, i get different outputs. So basically it seems that i have no idea what I'm doing.

Im doing Serial1.print('{', BIN); and sending each char at a time. After command is sent, I check if there is data in the serial buffer, read it into a byte, attach to a String, and print it out.

Hope we can reach somewhere with this!
Thanks!

LisandroLopes:
Regarding the code, i opted for not including, since I'm only trying to understand the basics of communication using binary data, and im not sure if my answers are making any sense, since they all seem random.

Then I'll opt not to respond anymore.

Seeing your code allows us to see what you're doing wrong and gives us hints as to what misconceptions you have. A common misconception about Serial data is that multi-byte responses all arrive simultaneously. Seeing your code would allow us to know if you've made that assumption.

I really don't see whats the difference in putting this lines of codes here. I know its incorrect, and i was just trying to understand to concept behind it, so I can do something useful :slight_smile: Would understand in other situation, but okay, I'm the one reaching out for help, so will do everything you ask! Sorry, come back!

byte c;
String inputString="";

void setup() {

// initialize serial:
Serial.begin(9600);
Serial1.begin(9600);
/*
Serial1.print('{',BIN);
Serial1.print('{',BIN);
Serial1.print('D',BIN);
Serial1.print('2',BIN);
Serial1.print('0',BIN);
Serial1.print('0',BIN);
Serial1.print('0',BIN);
Serial1.print('2',BIN);
Serial1.print('D',BIN);
Serial1.print('4',BIN);
Serial1.print('}',BIN);
Serial1.print('}',BIN);
Serial1.println();
*/
Serial.println('{{D20002D4}}',BIN);
Serial1.println('{{D20002D4}}',BIN);
delay(10);
while(Serial1.available()>0)
{
c=Serial1.read();
inputString+=c;
}

Serial.print("Answer: ");
//Serial.println(inputString);

Serial.println(inputString);
}

I'm totally aware that the command "attempts" there aren't the same, at least the representation is not the same so.. And even printing out one by one, the size of each sent data is different. Maybe there is the problem? Shouldnt it be uniform, all the data having same size, or is it irrelevant?

I'll go ahead and remove the commented out code, clean up the formatting and post the code with the proper tags:

byte c;
String inputString="";

void setup() 
{

  // initialize serial:
  Serial.begin(9600);
  Serial1.begin(9600);

  Serial.println('{{D20002D4}}',BIN);
  Serial1.println('{{D20002D4}}',BIN);
  
  delay(10);
  while(Serial1.available()>0)
  {
    c=Serial1.read();
    inputString+=c;
  }

  Serial.print("Answer: ");
  Serial.println(inputString);
}

void loop()
{
  
}

Lets start here:

Serial.println('{{D20002D4}}',BIN);

Those 12 characters can't fit into a single character, so you shouldn't be using single quotes. Furthermore, why are you using Serial.print with BIN? Does the device you are communicating with expect a stead stream of 48s and 49s (See the ASCII table)? To expand on this, the following line of code:

Serial1.print('{',BIN);

will send out 8 bytes of data: a combination of '1's and '0's. This is only really for display purposes, there isn't much in this method for communication between devices.

You're also using println, so does the device expect a line feed ('\n') as well? This is where data sheets come in handy. Assuming you just want to print out that string, just use:

Serial1.print("{{D20002D4}}");

That will only send the 12 bytes that are contained within the string. Printing the entire string as binary would send 12*8 or 96 bytes, which I doubt was your intention.

Now on to this:

delay(10);

What kind of response are you expecting? Are you positive 10 ms is enough time to send 12 bytes, and expect X amount of bytes back at the 9600 baud rate?

Arrch:
Lets start here:

Serial.println('{{D20002D4}}',BIN);

Those 12 characters can't fit into a single character, so you shouldn't be using single quotes. Furthermore, why are you using Serial.print with BIN? Does the device you are communicating with expect a stead stream of 48s and 49s (See the ASCII table)? To expand on this, the following line of code:

That actually makes sense that it didnt work " instead of ', check. About second part, well, As I was told the ECU only understands binary data. But how is the data sent out anyway? I'm having problems interpreting that " only understands binary data" comment. Every information sent is 0 and 1's no? And that was why i was sending in BIN, was one of my last attempts to see what would come out of it. But no, i Guess sending that much information wasnt my intention.

Arrch:

Serial1.print('{',BIN);

will send out 8 bytes of data: a combination of '1's and '0's. This is only really for display purposes, there isn't much in this method for communication between devices.

Yeah, i guess that was the point that I've just realized. Only for displaying purposes.

Arrch:
You're also using println, so does the device expect a line feed ('\n') as well? This is where data sheets come in handy.

Indeed. the data frame ends with the terminator }} and the ECU considers that it just received a full command.
So i should never use println when sending a command?

Regarding the delay, I'm not sure about how long the device takes to answer, Just know that it doesnt work instantly.

Running with the changes that you kindly suggested, i can go to next step of my problem. How to read data. I know that I can choose how i want to read information, can save the output of Serial.read() in some kind of variable type and it will convert to it. In this case, if im expecting to see the answer with something like {{D202XXXXCC}}, where XXXX are operation data from the ECU and CC is the byte related to Checksum, how should I save it?

Nevertheless, I should be getting consistent data, instead of

Answer: 25210214634209
Answer: 1231236850184
Answer: 1231236850112238
Answer: 197
Answer: 254243
Answer: 23038130130146226254

P.s.: Using serial.println() means that im sending ASCII data? Cause its a binary protocol. And im back to same confusion in m head.

I think most of your confusion can be attributed to a misunderstanding as to how data is stored/sent/represented.

As I was told the ECU only understands binary data

All devices only understand binary.

But how is the data sent out anyway?

In a stream of HIGHs and LOWs.

And that was why i was sending in BIN

It already sends it as binary (A stream of HIGHS and LOWs). When you print using BIN as the second argument, you are telling the microcontroller: "Take this single byte, 8 bit piece of data, convert it to a combination of 8 '1's and '0's, and send those 8 bytes of data over the serial port.

So i should never use println when sending a command?

Not necessarily. Using println works if the device you are sending to expects a new line after each command. Often times, I will use '\n' as a terminating character when communicating over UART with two microcontrollers.

Regarding the delay, I'm not sure about how long the device takes to answer, Just know that it doesnt work instantly.

Then I wouldn't use delay() as it is poor practice. Eventually, you'll want to build a state machine that handles the communications. This will give you the added advantage of being non-blocking. For now though, I would use a bigger delay (like a whole second) until you can reliably get the responses you are expecting.

Running with the changes that you kindly suggested,

When you make changes to the code, it's a good idea to post the updated code using the proper CODE tags.

how should I save it?

Depends on how you want to use it.

Nevertheless, I should be getting consistent data, instead of

Since I don't have the datasheet, I couldn't say why you are getting those values. Are you certain it expects a 12 byte command? D20002D4 can also be interpreted as HEX, which would make it an 8 byte command.

As you do this

Serial1.print('{',BIN);

you get 8 bytes? or 8 bits? { in ascii is 7B, so it will print 0111 1011 no? :cold_sweat:

What i basically was trying to do was to send
0111 1011 0111 1011 1101 0010 ... ....
7 B 7 B D 2 .... ....
{ {
From what i understood, Serial print is only for displaying purposes, so regarding communication between machines it doesnt really matter?

Yes, the only info i got from the company is the UART commands. D2 is the command for get parameter, and the structure of the frame is as i put in previous posts.

I will try to get the datasheet. Going crazy out here with this.

Thanks for the help

LisandroLopes:
you get 8 bytes? or 8 bits? { in ascii is 7B, so it will print 0111 1011 no? :cold_sweat:

Nope, you get 8 bytes:

'0', '1', '1', '1', '1', '0', '1', 1'

Note the single quotes. The BIN argument tells it to use the ASCII encoding of the binary value of the given character. '0' and 0 binary are not the same value, nor are the same bit-width:

'0' = 48 decimal = 0x30 = 0b00110000 // The character '0'
0 = 0 decimal = 0x0 = 0b0

What i basically was trying to do was to send
0111 1011 0111 1011 1101 0010 ... ....
7 B 7 B D 2 .... ....

As I suspected, you don't want to send 'D', '2', you want to send 0XD2. You can do something like this:

Serial.write('{'); // sends 0x7B
Serial.write('{'); // sends 0x7B
Serial.write(0xD2); // sends 0xD2
Serial.write(0x00); // sends 0x00
Serial.write(0x02); // sends 0x02
Serial.write(0xD4); // sends 0xD4
Serial.write('}'); // sends 0x7D
Serial.write('}'); // sends 0x7D

Both print and write still send binary data. The different is how they interpret the data to send. If the data provided is numeric, print will convert it to the ASCII representation which could be up to 3 bytes worth of data. write will just send the single byte of binary data:

Serial.print(2); // sends '2' = 0b01010000
Serial.write(2); // sends 2 = 0b00000010

For the former block of code, we can save a couple of lines of code by using an array:

byte command[] = { 
    {', '{', 0xD2, 0x00, 0x02, 0xD4, '}', '}' 
};
...
Serial.write(command, sizeof(command));