Hey. I've got a project, where I want to use my Arduino Uno as a slave and PC as RS485 Master.
I've got MAX485 module (TTL to RS485) and USB -> RS485 converter. My problem is when i try to send any data from master to arduino i am getting timeouts. I've tried several software on PC (simple modbus master, Qmodmaster a few others), but i am getting timeouts everytime. Everything is connected like here (except display and servo):
(source: RS485 MODBUS Serial Communication using Arduino UNO as Slave)
I've tried to change TX/RX cables, different USB ports etc, nothing helps). I hope someone can help me.
Looking at the display in the pictures I think there is some code involved but I don't see it here...
@Railroader
//RS-485 Modbus Slave (Arduino UNO)
//Circuit Digest
include<ModbusRtu.h> //Library for using Modbus in Arduino
#include<LiquidCrystal.h> //Library for using 16x2 LCD display
#include <Servo.h> //Library for using Servo Motor[/color]
#define led1 2 //Define as 2 led1
#define led2 5 //Define as 5 led2[/color]
LiquidCrystal lcd(8,9,10,11,12,13); //initizlize lcd object with pins (RS,E,D4,D5,D6,D7) for class liquid crystal
Servo servo; //Initilize servo object for class Servo
Modbus bus; //Define Object bus for class modbus
uint16_t modbus_array[] = {0,0,0}; //Array initilized with three 0 values
void setup()
{
lcd.begin(16,2); //Lcd set in 16x2 mode
lcd.print("RS-485 Modbus"); //Welcome Message
lcd.setCursor(0,1);
lcd.print("Arduino Slave");
delay(5000);
lcd.clear();
pinMode(led1,OUTPUT); //Led1 set as OUTPUT
pinMode(led2,OUTPUT); //Led2 set as OUTPUT
servo.attach(6); //Servo PWM pin 6
bus = Modbus(1,1,4); //Modbus slave ID as 1 and 1 connected via RS-485 and 4 connected to DE & RE pin of RS-485 Module
bus.begin(9600); //Modbus slave baudrate at 9600
}
void loop()
{
bus.poll(modbus_array,sizeof(modbus_array)/sizeof(modbus_array[0])); //Used to receive or write value from Master
if (modbus_array[0] == 0) //Depends upon value in modubus_array[0] written by Master Modbus
{
digitalWrite(led1,LOW); //LED OFF if 0
lcd.setCursor(0,0);
lcd.print("L1:OFF");
}
else
{
digitalWrite(led1,HIGH); //LED ON if value other than 0
lcd.setCursor(0,0);
lcd.print("L1:ON");
}
if (modbus_array[1] == 0) //Depends upon value in modbus_array[1] written by Master Modbus
{
digitalWrite(led2,LOW); //LED OFF if 0
lcd.setCursor(8,0);
lcd.print("L2:OFF");
}
else
{
digitalWrite(led2,HIGH); //LED ON if value other than 0
lcd.setCursor(9,0);
lcd.print("L2:ON");
}
int pwm = modbus_array[2]; //Depends upon value in modbus_array[1] written by Master Modbus
servo.write(pwm); //Write Received value (0 to 180) from Modbus Master
lcd.setCursor(0,1);
lcd.print("Servo angle:");
lcd.print(pwm); //Prints Angle in 16x2 LCD display.
delay(200);
lcd.clear();
}
I dont think LCD is important in this code. I've tried to delete all LCD and servo stuff, but it didnt solve my problem.
Thanks for your answer!
My first reaction is here: include<ModbusRtu.h> //Library for using Modbus in Arduino
Is that correct? Why not #include.....?
The diagram shows that the UNO hardware serial port is connected to the RS-485 driver. It's not a good idea to splice into the hardware serial port on the UNO to do serial comms to other devices. I think that you would have more success if you were to use a software serial port to drive the Modbus channel.
I would recommend AltSoftSerial from PJRC. However, it uses pins 9 & 8 on the UNO, so you would have to reconfigure the LCD wiring. You should be ok at 9600 baud, or even 19200 baud. The highest baud rate supported is stated as 31250.
Just typo, i've got #include in program. It wouldnt compilate if i left this without # symbol.
@markd833
I am not sure how it works, correct if i am wrong. Does "AltSoftSerial" library give me opportunity to left max485 unused?
Actually, my project is based on custom PCB (created by me for university project). I've put ATmega328, MAX485 and few other parts on my PCB. I want to send messages via RS485 to my PCB to do something (move motor for example). I use Arduino as a platform for tests and programming.
The use of a software serial port frees up the main hardware serial port for such things as debugging and loading new sketches. Most off the shelf boards have some sort of USB-to-serial device connected to the hardware UART.
The UNO RX input is connect to the TX output of the USB-to-serial device. If you connect the RS-485 module TX to the RX input as well, then you will most likely have problems with the USB-to-serial device wanting to keep the TX line high and the RS-485 module wanting to drive it low (for example).
You still need the MAX485 board when using the software serial port as it is needed to provide the correct voltage levels for the RS-485 bus.
Now, if you have a custom board (and I don't know how yours is wired up or what's on it), and you are ok with loading your code via the ICSP method (rather than via the bootloader and the USB-to-serial route), then you can use the real hardware UART to drive your RS-485 module.
I despise Fritzing diagrams. Just awful they are and this is a great example.
Did you catch that jumper on the breadboard between pins DE and RE on the RS-485 module?
PS: some Modbus libraries do not work with software serial. Which one are you using? Modbus that is.
You have to make your troubleshooting lower level. When you troubleshoot a "timeout" you're testing both the hardware, and lower level code in addition to the higher level code. In other words, a system. That is really difficult. You need to write some test sketches that only exercise limited aspects of the comm channel so you can get some data that sheds any light on the problem.
@markd833
This is how MAX485 is connected on my custom PCB. RX485 and TX485 are connected to pin2 (TX) and pin3 (RX) of ATmega328.
My plan was to make RS485 work on Arduino Uno and then edit program to make it work on my custom device. I've got kanda10 pin connector on my PCB for programming.
I think its not good idea to create a Software Serial communication on Arduino, when i've got hardware UART on PCB. I use arduino just for tests.
@WattsThat
Yep, i noticed that jumper, pins are connected.
PS: some Modbus libraries do not work with software serial. Which one are you using? Modbus that is
I've tried several libraries - SimpleModbusSlave, ArduinoModbus, SimpleModbusSoftwareSerial and AltSoftSerial.
@aarg
I agree, but i am not sure how should i start, when even basic communication doesnt work.
hardtofindanynick:
I agree, but i am not sure how should i start, when even basic communication doesnt work.
Did you post your basic communication sketch, or did I miss something? The code in reply #2 is way too complex for that. You probably need to create something simple for the PC end, too. As I implied, it's to rule out problems in the high level software.
Something simple like echoing a character....
If the PC USB adapter in the diagram is the one you are using, it has a time delay based bus enable (not hardware I/O controlled). So look for settings to accommodate that in the PC software.
As has been suggested, you need to start with something really basic to try and figure out which part of your system is not working correctly.
I would suggest that you take your Modbus slave device (i.e your UNO) and load up a very basic sketch that simply puts the RS485 module into receive mode and prints out every character/byte it receives over the RS485 link from your PC. Your PC will still complain about timeouts because it will receive no response to the message.
If you know the Modbus message you are trying to send from your PC, then you should see it printed out by your UNO. That should at least give you the confidence that the some of the basics are working.
EDIT: You could also try using a terminal emulator on your PC and typing in characters to see if they are printed out by your UNO. If that works, then amend the UNO code to echo back each received character over the RS485 link to the PC.
Yes, one way communication is safer than duplex with RS485 because there can't be any bus collisions.
Using your instructions, i made a huge research and tried several things. This is result:
Left window (COM8) is an Arduino Uno, right window (COM3) is a RS485->USB converter. I can send messages from COM8 (arduino) to COM3, but cant from COM3 to COM8. As u see, messages are corrupted (always random char / int). Currently TX and RX from MAX485 are connected to 2 and 3 pin, DE&RE to 4 pin.
Code:
// Includes
#include <ModbusRtu.h>
#include <SoftwareSerial.h>
// Defines
#define LED_PIN 5
#define SWITCH_PIN 6
// Variables
Modbus modbus_port;
SoftwareSerial mySerial(2, 3); // RX, TX
// modbus_array = { LED control, toggle switch state }
uint16_t modbus_array[] = {0, 0};
void setup()
{
while (!Serial) {
; // wait for serial port to connect. Needed for Native USB only
}
// Initiate a MODBUS object
modbus_port = Modbus(1, 1, 7);
// Start the serial port with a specified baud rate
modbus_port.begin(2400);
Serial.println("Goodnight moon!");
// set the data rate for the SoftwareSerial port
mySerial.begin(2400);
mySerial.println("Hello, world?");
pinMode(LED_PIN, OUTPUT);
pinMode(SWITCH_PIN, INPUT);
}
void loop()
{
// Allow the master to access the registry table
modbus_port.poll(modbus_array, sizeof(modbus_array)/sizeof(modbus_array[0]));
if (mySerial.available())
Serial.write(mySerial.read());
if (Serial.available())
mySerial.write(Serial.read());
// If the master device sets the first element in the array to 0, turn off the LED.
// Any other number will make the LED go high.
if (modbus_array[0] == 0) {
digitalWrite(LED_PIN, LOW);
} else {
digitalWrite(LED_PIN, HIGH);
}
// Set the second element in the array to the state of the switch
modbus_array[1] = digitalRead(SWITCH_PIN);
}
This is a code what i've been using in last few tries. PC master softwares still give me timeouts and dont send anything to arduino.
Too complicated. This is not what we asked you to do.
Hello again. I gave up already, thats so problematic. I decided to leave arduino part and focus on my PCB.
My PCB has MAX485 connected like this:
Atmega328 | MAX485
TX TX
RX RX
23 RE+DE
26 DC motor output1
15 DC motor output2
I want to make a simple program, which would set HIGH on DC motor output1 when PCB receives specific symbols from RS485 master.
I am using Arduino IDE and arduino as programmer for my ATmega328.
#include<ModbusRtu.h> //Library for using Modbus in Arduino
#define MotorOut1 A0 // (arduino A0 = pin23 of atmega328)
Modbus bus; //Define Object bus for class modbus
uint16_t modbus_array[] = {0,0,0}; //Array initilized with three 0 values
void setup()
{
pinMode(MotorOut1,OUTPUT); //set as OUTPUT
bus = Modbus(1,1,A3); //Modbus slave ID as 1 and 1 connected via RS-485 and A3 (a3 arduino = 23 of atmega328) connected to DE & RE pin of RS-485 Module
bus.begin(9600); //Modbus slave baudrate at 9600
}
void loop()
{
bus.poll(modbus_array,sizeof(modbus_array)/sizeof(modbus_array[0])); //Used to receive or write value from Master
if (modbus_array[0] == 0) //Depends upon value in modubus_array[0] written by Master Modbus
{
digitalWrite(MotorOut1,LOW); //LED OFF if 0
}
else
{
digitalWrite(MotorOut1,HIGH); //LED ON if value other than 0
}
delay(200);
}
Is my code correct?
of course not
It compiles, but nothing changes on pcb pins.
I am using QmodMaster on PC, this is what i got everytime:

So you've decided to avoid writing a Minimum Reproducible Example as suggested, and instead gone off and written an entirely new program that also fails? Am I getting this right?