I have a system using a LOLIN mini d1 that reads a battery BMS via RS485. The library works fine after a few tweeks. Now I am trying to use it with a MKR1400 to send the MQTT data via GSM.
I have encountered an issue that really puzzled me. I am using a MAX485 and I need to turn DE and RE high for sending and low for receiving. I do that in the library. Below are very simplified library to debug. If I mark out delay then the pin goes high and sends but I can not receive, with the delay set the pin stays low. I could understand that it disturbs the serial but not setting the pin high or up.
h file
#ifndef SERIALTEST_H
#define SERIALTEST_H
#include "Arduino.h"
class ETDBms {
public:
ETDBms(); // Constructor
void begin(Uart &port);
void SerialTxControl(uint8_t pinTx);
void SerialRxControl(uint8_t pinRx);
void main_task();
void readSerial(); // New member function to read from serial port and write to serial monitor
private:
bool is_initialized;
Uart* serial;
uint8_t _pinTx;
uint8_t _pinRx;
};
#endif // SERIALTEST_H
cpp file
#include "SerialTest.h"
// Constructor
ETDBms::ETDBms() {
is_initialized = false;
}
// Start processing
void ETDBms::begin(Uart &port) {
serial = &port;
is_initialized = true;
}
// Set the Rx and Tx pins
void ETDBms::SerialTxControl(uint8_t pinTx) {
_pinTx = pinTx;
}
void ETDBms::SerialRxControl(uint8_t pinRx) {
_pinRx = pinRx;
}
// Call this as fast as possible within the sketch's loop() function
void ETDBms::main_task() {
if (is_initialized) {
// SET the RS485 shield to transmit mode
digitalWrite(_pinTx, HIGH);
digitalWrite(_pinRx, HIGH);
serial->print("test"); // Sending "test" over the serial port
// SET the RS485 shield to receive mode
digitalWrite(_pinTx, LOW);
digitalWrite(_pinRx, LOW);
delay(2000); // Delay for readability
}
}
// Read from Serial1 port and write to serial monitor (Serial)
void ETDBms::readSerial() {
if (serial->available()) {
Serial.print("Received from Serial1: ");
while (serial->available()) {
char c = serial->read();
Serial.print(c);
}
Serial.println();
}
}
and the sketch
#include "SerialTest.h"
ETDBms bms;
int pinRX = 2;
int pinTX = 3;
void setup() {
pinMode(pinRX, OUTPUT);
pinMode(pinTX,OUTPUT);
Serial.begin(115200);
Serial1.begin(9600);
bms.begin(Serial1); //baud rate 9600
bms.SerialRxControl(pinRX);
bms.SerialTxControl(pinTX);
}
void loop() {
bms.main_task();
//bms.readSerial();
}
Am I missing something specific to the MKR1400?
I tried using the code in the sketch directly but I still encounter weird Low/high behaviour. I removed all the delays in my library but it did not help.
My MAX485 will not send/recieve properly with this issue as it is not set properly. I am quite positive that the library will work once this issue is solved.
I did not test your code so technically this is not a definitive answer, but I see a few issues regarding your library and it is also too long as a comment, so I provide my suggestions and comments here.
int pinRX = 2;
int pinTX = 3;
First, I assumed those are DE pin and RE pin respectively, personally I preferred to name them that way instead of to be confused as TX and RX pins. I will use pinRE
for pinRX
and pinDE
for pinTX
for the rest of the text below.
serial->print("test")
does not send out data immediately, it adds the data to the transmission queue and send in a rather slow baud rate (in your case, 9600 baud), so your code prematurely terminate the DE pin. In order to make sure that the data has been sent out, it should call serial->flush()
prior deactivate the DE pin.
The delay(2000)
is not necessary, however, toggle the DE pin take time, especially when you have a long RS485 cable, it is advisable to have a delay of 50us (or longer, read the datasheet and RS485 spec) prior or after the actual data transmission.
So here is the modified code for data transmission
digitalWrite(_pinDE, HIGH);
delayMicroseconds(50); // this delay may or may not need longer
serial->print("test"); // Sending "test" over the serial port
serial->flush(); // make sure all data are sent
delayMicroseconds(50);
digitalWrite(_pinDE, LOW);
For receiving, you will just need to put the MAX485 in receive mode (i.e. RE pin at LOW) by default, and only toggle the DE pin during transmission.
void setup() {
// your original setup code here
digitalWrite(pinRE, LOW); // in receive mode by default
}