Hello,
This is my first-ever forum post.
I am trying to demonstrate some simple MODBUS communication between an Arduino MKR GSM 1400 with an MKR RS485 shield that's connected to a MODBUS-enabled device. I've already demonstrated proficiency with an Arduino Mega & ESP32 alongside a TTL to RS485 (SCM TTL to RS-485 Interface Module - ProtoSupplies) and the device in question, but I really need cellular connectivity hence the use of the MKR board. When I tried to use the linked TTL to RS485 converter I never saw signs that it was able to work. Why is that? Is it incompatible or is there some weird way it needs to connect? Straight connecting to RX and TX had no communication when I ran the code I'm confident should work.
I believe I'm close to having it working with the MKR shield. See the attached connection diagram:
Here is the current code:
#include <MKRGSM.h>
#include <ArduinoRS485.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <Wire.h>
typedef uint8_t Uint8;
typedef uint16_t Uint16;
typedef uint32_t Uint32;
char Buff[100];
Uint16 myMessage[7];
int numAvailable = 0;
int refTypeCloud = 0;
void setup() {
RS485.begin(19200);
Serial.begin(19200);
pinMode(LED_BUILTIN, OUTPUT);
RS485.beginTransmission();
RS485.receive();
}
void loop(){
delay(500);
readRefType();
delay(500);
Serial.println();
if(RS485.available() > 0){
delay(1000);
numAvailable = RS485.available();
Serial.println();
Serial.print("Available: ");
Serial.println(numAvailable);
Serial.println();
delay(1000);
for(int i = 0; i < numAvailable; i++){
int myByte = RS485.read();
if(i==0){
Serial.print("Ref Type: ");
}
Serial.print(myByte);
Serial.print(" ");
myMessage[i] = myByte;
}
}
Serial.println();
uint16_t refType = (myMessage[3]*256) + myMessage[4];
refTypeCloud = refType;
Serial.print("Ref Type: ");
Serial.println(refType);
Serial.print("Ref Type: ");
Serial.println(refTypeCloud);
Serial.println();
Serial.println();
delay(2000);
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
// MODBUS function code for reading the value that represents the type of refrigerant (0-6)
void readRefType(){
Uint8 buff[8];
Uint16 CRC;
int len = 6;
buff[0] = 02; //Slave address
buff[1] = 04; //Function code write 1 register (6)
buff[2] = 00; //Register address: high byte
buff[3] = 139; //Register address: low byte
buff[4] = 00; //Data to write: high byte 0
buff[5] = 01; //Data to write: low byte 0
CRC = ModRTU_CRC(buff, len);
buff[6] = CRC;
buff[7] = CRC >> 8;
for (int n = 0; n < 8; n++)
{
RS485.write(buff[n]);
}
delay(1000);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
// Compute the MODBUS RTU CRC
Uint16 ModRTU_CRC(byte buf[], int len){
Uint16 crc = 0xFFFF;
for (int pos = 0; pos < len; pos++) {
crc ^= buf[pos]; // XOR byte into least sig. byte of crc
for (int i = 8; i != 0; i--) { // Loop over each bit
if ((crc & 0x0001) != 0) { // If the LSB is set
crc >>= 1; // Shift right and XOR 0xA001
crc ^= 0xA001;
}
else { // Else LSB is not set
crc >>= 1; // Just shift right
}
}
}
// Note, this number has low and high bytes swapped, so use it accordingly (or swap bytes)
return crc;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
And here is the current output for said code:
16:44:00.984 -> Available: 8
16:44:00.984 ->
16:44:01.998 -> Ref Type: 2 4 0 139 0 1 65 211
16:44:01.998 -> Ref Type: 35584
16:44:01.998 -> Ref Type: 35584
This output is the MODBUS "read" command being sent to the device. What I would like to see in the serial monitor is the response of the device to the read command. I have never used this ArduinoRS485 library before. I'm guessing the use of it's functions is where I'm going wrong. Thanks in advance for any help.