Integrating ESP32-C3 with TTL-to-RS485 for Wind Speed and Direction Sensor Data via Modbus
Connect an RS-FS-N01 wind speed sensor and RS-FX-N01 wind direction sensor to an ESP32-C3 using a TTL-to-RS485 converter. Use Modbus RTU over RS485 to query and parse measurements.
Hardware Setup
- ESP32-C3 board
- TTL-to-RS485 module
- RS-FS-N01 wind speed transmitter
- RS-FX-N01 wind direction transmitter
Serial Configuration
Configure UART1 on the ESP32-C3 for 9600 baud, 8 data bits, no parity, 1 stop bit (8N1), and assign RX/TX pins.
#include <Arduino.h>
#include <HardwareSerial.h>
HardwareSerial rs485Serial(1);
const uint8_t RS485_RX_PIN = 2;
const uint8_t RS485_TX_PIN = 3;
void setup() {
Serial.begin(9600);
rs485Serial.begin(9600, SERIAL_8N1, RS485_RX_PIN, RS485_TX_PIN);
}
Bidirectional Bridge Between USB Serial and RS485
To forward traffic between a PC serial monitor and the RS485 bus, implement a relay function:
void relayTraffic() {
String buffer = "";
if (Serial.available()) {
buffer = Serial.readString();
Serial.print(buffer);
delay(10);
rs485Serial.print(buffer);
}
if (rs485Serial.available()) {
buffer = rs485Serial.readString();
delay(10);
Serial.println(buffer);
}
}
Testing can be done by sending a Modbus request from a terminal, e.g., 01 03 00 00 00 01 84 0A. A correct response such as 01 03 02 00 00 B4 44 confirms proper wiring and protocol handling.
Automated Query of Wind Speed Sensor
Instead of manual terminal input, embed Modbus queries in firmware. Define a request frame and send it as raw bytes.
#include <HardwareSerial.h>
extern HardwareSerial rs485Serial;
const uint8_t windSpeedReq[] = {0x01, 0x03, 0x00, 0x00, 0x00, 0x03, 0x84, 0x0A};
void requestWindSpeed() {
rs485Serial.write(windSpeedReq, sizeof(windSpeedReq));
}
Parsing the Response
Read incoming bytes, accumulate them, and extract measurement values based on Modbus byte positions.
void processWindData() {
String rawBytes = "";
while (rs485Serial.available()) {
uint8_t byteVal = rs485Serial.read();
Serial.println(byteVal, HEX);
rawBytes += String(byteVal) + ',';
}
Serial.println(rawBytes);
int sepIndex = -1;
String parts[8];
for (int idx = 0; idx < 8; idx++) {
sepIndex = rawBytes.indexOf(',');
if (sepIndex != -1) {
parts[idx] = rawBytes.substring(0, sepIndex);
rawBytes = rawBytes.substring(sepIndex + 1);
} else {
if (rawBytes.length() > 0) {
parts[idx] = rawBytes;
}
}
}
int highByte = parts[3].toInt();
int lowByte = parts[4].toInt();
float speed = (highByte * 256 + lowByte) / 10.0;
Serial.print("Wind speed: ");
Serial.println(speed);
}
Main Loop Integration
Combine transmission and reception steps in the continuous loop:
void loop() {
requestWindSpeed();
delay(1000);
processWindData();
}
Ensure write() is used for sending binary frames instead of print(), preserving exact byte values.
Key Considerations
- Adhere to Modbus RTU framing: correct slave ID, function code, register addresses, CRC placement.
- Recalculate CRC16 for each request when required.
- Interpret register pairs correctly to reconstruct multi-byte numeric values.
- Use raw byte reads/writes for reliable transport of non-ASCII data.
- Implement transparent bridging during development to validate physical layer communication.