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.
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.
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
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.
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) {
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.
Communication between ESP32 and Modbus device now working. As @jremington said the problem was not in the code itself , i had two issues:
Visual Code serial monitor not working correctly (Working now with update)
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.