I am on a quest to use the RS485 to communicate between two 3216.
Indeed, only 1 USART on board, which is already giving me headaches about debugging. Trying to get around via leds. Anyway, each 3216 has a transceiver and those are connected via the AB.
I am using the megaTinyCore, all good, however, I am new to the RS485, namely Serial on Arduino. So, wondering, if the RS485.h from Arduino supports/works with the megaTinyCore and its Serial setup?
If I recall correctly, the ArduinoRS485 (is that the one you are referring to?) library is for use with the MKR range of Arduinos.
If you have basic serial Tx & Rx working, then assuming your RS485 module isn't one of the auto switching ones, all you need to do is switch the RE & DE signals when you move between Tx and Rx. If you are using a hardware UART, then wait till all the data has been transmitted before switching back to Rx mode - use the flush function.
Thanks, interesting, when you say "is not one of the auto-switching one",
what do you exactly mean?
I guess that with the pin "XDIR", namely by the direction is this switching defined?
For example, I am connecting the RXD, TXD and XDIR to the 3216 and got basic across.
However, not sure how the Serial lib works.
The code for the Master:
// "MASTER"
byte red = 0;
byte green = 1;
byte brightness;
byte fadeAmount = 1;
byte i = 0;
void setup() {
pinMode(red, OUTPUT);
pinMode(green, OUTPUT);
//rs485 setup
Serial.swap(0);
Serial.begin(115200, SERIAL_RS485 );
}
void loop() {
brightness = brightness + fadeAmount;
//up and down ...
if ( brightness <= 0 || brightness >= 254 ) {
fadeAmount = -fadeAmount;
}
//sending brightness to the slave
if (Serial.availableForWrite()) {
Serial.write(brightness);
}
//testing the led
//analogWrite(red, brightness);
} //END of "master"
Code for the Slave.
//"SLAVE"
byte incomingByte; // incoming serial data
byte green = 0;
void setup() {
pinMode(green, OUTPUT);
//setting up the RS485
Serial.swap(0);
Serial.begin(115200, SERIAL_RS485 );
while (!Serial) {
; // wait for serial port to connect. Needed for native USB
}
//checking that the led green works!
blinkLed(green, 3);
//wait a bit ?
delay(1000);
}
void loop() {
// read the incoming byte:
if ( Serial.available() ) {
incomingByte = Serial.read();
}
analogWrite(green, incomingByte);
// OK!
//if (incomingByte < 3) {
//blinkLed(green, 3);
//}
} //end of loop
// a quick led blinker
void blinkLed(byte a, byte b) {
for (byte i = 0; i < b; i++) {
digitalWrite(a, 0);
delay(100);
digitalWrite(a, 255);
delay(100);
digitalWrite(a, 0);
}
}
if(incominigByte>3) is used works just ok,
however, I would like to be more specific and this is where it is not working,
for example, i++; //this will go up to 255, its a byte
if (Serial.availableForWrite()) {
Serial.write(i);
}
There are generally 2 variants of RS485 modules discussed here in the forum. There is the plain old RS485 module that requires the user to drive the RE & DE signals (or XDIR In your case where RE & DE are likely combined). Then there is the other type that includes additional circuitry to detect activity on the TxD line and automatically switch the RS485 transceiver into transmit mode and then back to receive mode after a short period of TxD inactivity.
With regards to actual code, this is off the top of my head for your master so beware:
//sending brightness to the slave
if (Serial.availableForWrite()) {
digitalWrite( xdirPin, HIGH );
Serial.write(brightness);
Serial.flush();
digitalWrite( xdirPin, LOW );
}
You would need to define which pin is the connected to the XDIR signal and check that setting it high causes the RS485 module to enter transmit mode.
The basics of the process are:
put the RS485 module into transmit mode
send the data
wait for the date to be sent
put the RS485 module into receive mode
Step 3 is important to get right. When you write to the serial port, you are actually writing to a buffer that holds the data, sending out each byte in turn. The call to serial.write will return as soon as the data is copied into the buffer, which is not when all the data has been transmitted.
For your receiver, because it currently only receives, you simply set your RS485 module to receive mode in your setup code and then you can listen for data in your loop.
Nick Gammons RS485 web page that @sterretje linked to in post #3 is a good introduction to the world of RS485.
Something to be aware of when using an Arduino with RS485, is that when it's in receive mode, you can't load new software via the USB port. That's because the external RX pin is in conflict with RX from the USB converter, and the hardware is set up so that the external pin wins, thus locking out USB. To make programming possible, you have to ensure that the default mode is "transmit", but that sends unwanted characters down the RS485 line to anything else that's connected. The ideal way to wire the RS485 interface would be to control the DE and RE lines separately, so that during programming, both of them would be disabled.
Thanks to both of you, so ideally I should reserve a pin, namely XDIR that I will set manually?
I was hopping this is done by the library... Anyway, here is the code, I guess the change to receive the data should be in Serial.read(), namely
//receive brightness at the slave
if (Serial.availableForWrite()) { //what is here needed, if anything?
digitalWrite( xdirPin, LOW ); //Receiver enable input
Serial.write(brightness);
Serial.flush(); //is this needed here too?
digitalWrite( xdirPin, HIGH ); //driver enable input?
}
byte ledPin = 0;
byte brightness;
byte xdirPin = 9;
byte fadeAmount = 1;
byte i = 0;
void setup() {
pinMode(ledPin, OUTPUT);
//rs485 setup
Serial.swap(0);
Serial.begin(115200, (SERIAL_HALF_DUPLEX | SERIAL_RS485));
// // normal serial !
// Serial.swap(1);
// Serial.begin(9600);
}
void loop() {
brightness = brightness + fadeAmount;
//up and down fading rutina?
if ( brightness <= 0 || brightness >= 255 ) {
fadeAmount = -fadeAmount;
}
//Serial.println(brightness);
delay(5);
analogWrite(ledPin, brightness);
//sending brightness to the slave
if (Serial.availableForWrite()) {
digitalWrite( xdirPin, HIGH );
Serial.write(brightness);
Serial.flush();
digitalWrite( xdirPin, LOW );
}
}
Yes, you need a pin available to control the direction of the data. However, if your master only ever transmits and your slave only ever receives, then you could tie your XDIR pins high and low as appropriate.
I'm not sure what the above code is attempting. The first comment says receiving but the code is sending....?
That looks better, however this line from your earlier code may be wrong:
I've only had a quick read of the megaTinyCore docs (on a small screen so likely I may have missed something) but I get the impression that the half duplex value may tell the hardware to send and receive data on the same pin. This isn't what you need as the RS485 module will have separate TxD and RxD signals.
I've just read this (also on my small screen):
In RS485 mode, at initialization, the HWSerial class configures the XDIR pin as an OUTPUT. 1 bit-time prior to sending any data, the XDIR pin will be driven HIGH. If using RS485, this should be connected to the external line driver IC to enable transmit. XDIR will be lowered 1 bit-time after the last bit has been sent.
So now I realise that the XDIR you talked about is a pin on the Arduino and not on the RS485 module!
The documentation suggests that the hardware will handle the XDIR signal all by itself. If that's the case, then you don't need to worry about controlling XDIR in your code or using the flush function either.
I think you should remove the SERIAL_HALF_DUPLEX as you want the hardware UART to use 2 pins rather than 1.
Ok, so the half duplex was removed, Serial.begin(115200, SERIAL_RS485);
I cannot get it to work
For example, if I change the brightness value at the sender, this is not received by the receiver.
Wondering what I am missing? BTW how to check, if my transceivers are working properly?
If you only have 2 devices, then you can remove the transceivers completely from the equation and wire directly between the boards. That way you can check your Comms without having to deal with direction control.
If you are using the RS485 modules, make sure that your master TxD signal is going to the correct pin on your RS485 module.
Does your RS485 module have any LEDs to indicate Tx or Rx? You can slow the baud rate down so the transmission takes longer which should keep the LED on for longer giving you a better chance if seeing it flicker.
Does page 325 of the 3216 datasheet help you out with the connections?
You might want to share a drawing of how you have wired the two 3216s together via their RS485 modules. Which RS485 modules are you using?
flush() returns when the last byte is placed in the TX register, not when that byte is completely transmitted. So making xdirPin low too early will block the transfer.
You are advised to wait one byte time before changing the xdirPin again after the flush().
You have control over both sides; therefore you can delay the reply in the slave slightly; this guarantees that the reply is not started by the slave while the master is switching the xdirPin.
I've no experience of using a 3216 in this particular configuration where the UART hardware has an additional output to specifically control the direction of data of an RS485 transceiver. All my encounters with RS485 have involved manually handling this.
@sterretje it appears from my brief read of the TINY3216 datasheet UART section that the 3216 can handle the direction control of an RS485 transceiver automatically via its XDIR pin. If the UART is configured correctly, then software control of the RS485 transceiver direction and the usual waiting for the serial transmission to complete may no longer be required.
In RS485 mode, at initialization, the HWSerial class configures the XDIR pin as an OUTPUT. 1 bit-time prior to sending any data, the XDIR pin will be driven HIGH. If using RS485, this should be connected to the external line driver IC to enable transmit. XDIR will be lowered 1 bit-time after the last bit has been sent.
You've not shared the design schematic so I'm guessing here. Is the pin defined by your variable txEnPin the same pin as the XDIR pin on the actual chip?
The datasheet says that XDIR is on port pin PB0 which is either chip pin 16 (for the VQFN package) or chip pin 11 (for the SOIC package) OR if the design used the alternate pin it's on port pin PA4 which is either chip pin 5 (for the VQFN package) or chip pin 2 (for the SOIC package).
BUT if it's not one of those pins, then you have to manually control the RS485 transceiver as you currently are.
IF you are doing it manually, then I think you should remove the SERIAL_RS485 parameter too as that may drive the XDIR pin and interfere with that pins usage in your design - assuming you are using that pin.
Anything really. An LED with associated resistor can be used to show activity on a pin - we would set the baud rate to the lowest it can go just to give us a chance of seeing a flicker. Maybe one of the ultra cheap 24MHz logic analyser boards or an oscilloscope.
We should be able to get you going without any of those but you would need to share your design in order for us to see if we can spot anything obvious and/or maybe even duplicate your setup.