Send.write() not sending numbers above 127 right

Hi,

I have stumbled on a strange thing, please help me because it might be something obvious.

Im trying to send an array of modbus data manually : 01 03 00 0a 00 02 e4 09 to serial port using ESP32 serial2:

#include "Arduino.h"
void setup() {
 
  Serial.begin(9600);
  Serial2.begin(38400);
  // This delay gives the chance to wait for a Serial Monitor without blocking if none is found
  delay(1500); 
 
}

void leerFlujo() {

  const uint8_t comando[8] = {1, 3, 0, 10, 0, 2, 228, 9}; // 01 03 00 0a 00 02 e4 09
  

  Serial2.write(comando,sizeof(comando));
}

void loop() {
  // send data every two second
  leerFlujo() ;
  delay(2000) ;
  

}

Modbus device is not responding and i discovered why, when monitoring serial2 output i get:
01 03 00 0a 00 02 fffd 09

0xe4 or 228 is not being sent correctly, in fact any number above 127 is being sent as FF FD. Please can you try this on your board and tell me if i am doing something wrong or the ESP32 has a bug with this serial library of arduino.

I have tried this code with python in my computer and on micropython, and it seems to work , data is being sent as the const array.

Thank you

No, that is how it is being printed by the receiver, which is probably where the error is. Please post the receiver code, using code tags.

Serial.write() sends only the commanded number of individual bytes.

2 Likes

As a receiver im using my laptop with visual studio code and a serial monitor terminal with read as HEX . I would use Arduino monitor but it doesnt have the show as hex option.

I send this command with python in my computer to the ESP32 and then read back the data from it to check on the array being sent and its ok.
I have tried to sent the array directly from VC serial monitor and i get the modbus device to respond because it sends the array well.

Also i got into this trouble of sending the mudbus command manually because the ArduinoMaster library i was using before didnt work and after checking the ESP32 output it gave me the same ff fd where E4 should be. Im beginning to think is a bug in my particular ESP32 board, i will try to use another one later.

Any Arduino can receive bytes of data over serial, and print the values in HEX notation on the serial monitor, using a command like Serial.print(byte_value,HEX);.

Serial.write() is thoroughly debugged and has been in constant use by millions of people, for many years. It is virtually certain that the errors you are encountering are in the part of the project you have not described.

1 Like

do you have you serial monitor terminal and the modbus device both on Serial2?

or was your test done only with the arduino and the Serial terminal? how did you connect your PC to to Serial 2?

Your are right, i didnt use it because i shows 00 as 0 and i wanted to see the full byte because sometimes you send several 00 and it confuses me when counting bytes. I beleive arduino folks could just enable see as hex .

When i do that i get from the arduino monitor : 130A02E49 instead of
01 03 00 0a 00 02 e4 09

The "crowding" is simply a matter of programming. Send leading zeros if necessary, and add a blank between printed bytes.

e.g.

if (byte_value < 0x10) Serial.write('0');
Serial.print(byte_value,HEX);
Serial.write(' ');

If you want help with code, post the code using code tags and explain what it is supposed to do and what it does instead.

You're on an ESP32, use printf()!

  uint8_t dataByte = 0x0F;
  Serial.printf("%.2hhX\n", dataByte);
1 Like

Thank for showing me how to print on serial formatted as 0x00. Still I need to just send the raw 0xe4 and for that there is the serial.write function. I will make more test to see why my board isnt sending numbers above 127 right.

write() always sends bytes (between 0x00 and 0xFF). If you think it's not sending values above 127, then your perception / interpretation of what you're seeing is simply incorrect.

1 Like

You are still assuming that the problem is in the sender. That assumption is wrong.

1 Like

You did not answer this

Hello,

Im using a manhattan USB-serial converter to communicate to Serial2 and the on board usb-serial to communicate with Serial1.

After looking around, I found an issue with Visual Code serial monitor. Every time a number greater than 127 was sent the data was incorrectly shown.

Good news is that this has a fix and its a reported bug to visual code developers:

Now it works:

I really like VisualCode Serial monitor because it enables me to view raw Hex data directly and works as a second serial monitor.

As jremington said. The real issue is on the hardware/software at some level.Cant figure out yet.

ModbusDevice --PC Read/writeOK
ESP32 ---PC Read/writeOk (tested on serial1 and 2,)
ModBusDEvice---ESP32 Not ok (sending/receiving data over serial2)

I connected ESP32 to PC, and it seems to be sending hex data ok

The problem is at hardware level between esp32 and the modbus device somewhere. Its not the cables because i have tested with straight and cross cables, continuity tests.

By the way im using a MAX232 connected at 3.3V supply so it doesn't damage esp32 pins. It works ok (esp32--PC) despite max232 vcc not 3.3v compatible. I will try to get my hands on a max3232 soon to check if that's the deal between those two.

Thank y'all

My code to send data over serial2 and get response on serial1 (works ok only with pc, i know ive checked with cross cables too)

static unsigned long incomingByte;
static unsigned long time_now = millis();


void setup() {
 
  Serial.begin(38400);
  Serial2.begin(38400, SERIAL_8N1, 16, 17);
  // This delay gives the chance to wait for a Serial Monitor without blocking if none is found
  delay(1500);
   
}

//Leer  2 registros de flujo en direccion 400010, 2 registros de 16 bits cada uno 01 03 00 0a 00 02 e4 09
void leerVantageFlujo() {


  //uint8_t flujo[9];// Definicion de variables Modbus
  //const char comando[16] = {0x0,0x1,0x0,0x3,0x0,0x0,0x0,0xa,0x0,0x0,0x0,0x2,0xe,0x4,0x0,0x9};
  // const uint8_t comando[8] = {0x01, 0x03, 0x00, 0x0a, 0x00, 0x02, 0xe4, 0x09};
  const uint8_t comando[8] = {0x01, 0x03, 0x00, 0x0a, 0x00, 0x02, 0xe4, 0x09};
  //Serial.write(comando,sizeof(comando));
  Serial2.write(comando,sizeof(comando));  
   
} 

void loop() {
  // send data only when you receive data:
  
  
   if (Serial2.available() > 0) {

    // read the incoming byte:
      incomingByte = Serial2.read();
      // Do something with bytes
      //Serial.write(11);
      Serial.write(incomingByte);
  }

//Non blocking delay
  if(millis() >= time_now + 3000){
        time_now += 3000;
        //Serial.write(10);
        leerVantageFlujo();
    }
  
  
  

}




CoolTerm would let you see that too if you want something standalone


Not your issue but

IncomingByte does not be an unsigned long, read returns an int you could be fine with just a byte as this is what write will use

Your millis based timing won’t work well when millis() rolls over, write it as a subtraction instead of an addition
if(millis() - time_now >= 3000ul) {

1 Like

It seems to me the problem is in your code. A typical source of such errors is incorrect conversion between bytes, integer and long types.

If this a byte, why do you defined it as long?

agreed - it's sounds as a byte with high end bit set to 1 (> 127 then) was read a signed value and promoted to an int16_t and thus the negative bit propagated although it does not meet what OP said

CitancomingByte does not be an unsigned long, read returns an int you could be fine with just a byte as this is what write will use

Got it. i was experimenting with several ways to declare variables and forgot that one. I changed it to int8_t

Your millis based timing won’t work well when millis() rolls over, write it as a subtraction instead of an addition

Another good tip about the millis() , will change that too. Appreciate it.

Just for fun and experiment sake, i wrote a micropython code to another esp32 that sends the same hex data over serial2 and listens for responses. I tested using the serial monitor, it works, I can send an hex value and see the value printed on the micropython terminal. Cant get a response from the modbus device though. If i send the exact same hex value using my computer, i do get a response. That's why i think is something hidding in the hardware.

from machine import Pin
from time import sleep
from machine import UART

serial = UART(2,38400)
led = Pin(2, Pin.OUT)



while True:
     led.value(not led.value())
    command= bytes.fromhex("0103000a0002e409")
    serial.write(command)
    if (serial.any() >0):
        print(serial.read()) 
        
    else:
        print("Zero")
        
    sleep(2)

I just ordered a MAX3232 online, hope that will do the trick.

Happy weekend

Hello everyone,

Communication between ESP32 and Modbus device now working. As @jremington said the problem was not in the code itself , i had two issues:

  1. Visual Code serial monitor not working correctly (Working now with update)

  2. MAX232N chip doesn't work well between ESP32 and Modbus device, strange thing is it worked between PC and ESP32, neverless I changed to MAX3232 because it's 3.3V fully compatible, and now it works good.

Great forum and great people. Thank you all.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.