Skip to content
Snippets Groups Projects
Commit 05607066 authored by amedvedova's avatar amedvedova
Browse files

Added a working example of for a soil moisture sensor.

parent 29cb498a
No related branches found
No related tags found
1 merge request!18Power management satellite
#include "Arduino.h"
#include <SoftwareSerial.h> // RS485 setup with ESP32
// THIS SNIPPET APPLIES ONLY TO SOIL SENSORS!!!
// Other RS485 sensors will have to use other commands as well
/*
TODO It would be better to have one class for ALL RS485 sensors since they
all send/receive data in the same way, and then specific classes for individual
sensors (soil moisture, rain gauge, radiation) with sensor-specific commands.
*/
/* TODO The address of the sensor (first byte of the query frame) is
hard-coded now - it should be passed as an argument instead since
we have three sensors with different addresses now.
The last two values of the queryFrame don't matter, they will be changed
later to confrom to the CRC check.
The length of the sent message will always be 8 bytes.
*/
const byte bufferSize = 6;
byte queryFrame[bufferSize + 2] = {0x05, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00};
// 0: sensor address (differs per sensor)
// 1: function code (03 = get data for all sensors)
// 2+3: register start (0x00 0x00 for all sensors)
// 4+5: register length (0x01 for radiation+rain, 0x02 for soil)
// 6+7: CRC check (calculated later per sensor and message)
/*
TODO the length of the answer frame should NOT be hard-coded, it's going to be either
8 bytes (radiation, rain) or 9 bytes (soil)
*/
byte answerFrame[9];
#define RXPin 4 // Serial Receive pin
#define TXPin 5 // Serial Transmit pin
// RS485 control
// this will change once we get different hardware
#define SERIAL_COMMUNICATION_CONTROL_PIN 6 // Transmission set pin
#define RS485_TX_PIN_VALUE HIGH
#define RS485_RX_PIN_VALUE LOW
SoftwareSerial RS485Serial(RXPin, TXPin); // RX, TX
unsigned int calculateCRC()
// TODO pass the query/answer frame into this and return the changed frame
// to make things neater maybe? Apparently there are also libraries for this...
// Change the last two bytes of the queryFrame to conform to a CRC check
// Yes, this is necessary. No, I don't know exactly what it does.
{
unsigned int tmp1, tmp2, flag;
tmp1 = 0xFFFF;
for (unsigned char i = 0; i < bufferSize; i++)
{
tmp1 = tmp1 ^ queryFrame[i];
for (unsigned char j = 1; j <= 8; j++)
{
flag = tmp1 & 0x0001;
tmp1 >>= 1;
if (flag)
tmp1 ^= 0xA001;
}
}
// Reverse byte order.
tmp2 = tmp1 >> 8;
tmp1 = (tmp1 << 8) | tmp2;
tmp1 &= 0xFFFF;
queryFrame[bufferSize + 1] = tmp1;
queryFrame[bufferSize] = tmp1 >> 8;
return tmp1; // the returned value is already swapped - CRC_L byte is first & CRC_H byte is last
}
void setup() {
// configure the pin to be output only
pinMode(SERIAL_COMMUNICATION_CONTROL_PIN, OUTPUT);
// Set data rates: Serial baud rate has to be WAY HIGHER than RS485Serial!
Serial.begin(115200);
RS485Serial.begin(4800);
// Calculate the check bytes: changes the last two bytes of queryFrame
calculateCRC();
// Print the message that's sent to the sensor
Serial.println("Query bytes:");
for (int i = 0; i < sizeof(queryFrame); i++){
Serial.print(queryFrame[i], HEX);
Serial.print(" ");
}
Serial.println();
Serial.println();
}
void loop() {
// Index for the readout while loop
int idx = 0;
int byteReceived;
float vwc; // volumetric waetr content, i.e. soil moisture
float temp; // soil temperature
// Initialize the transmitter
Serial.println("Sending data");
digitalWrite(SERIAL_COMMUNICATION_CONTROL_PIN, RS485_TX_PIN_VALUE);
// Send message: request a reading from the sensor
RS485Serial.write(queryFrame, sizeof(queryFrame));
// Initialize the receiver
digitalWrite(SERIAL_COMMUNICATION_CONTROL_PIN, RS485_RX_PIN_VALUE);
// Read out data: this works ONLY when the Serial baud rate >> RS485Serial baud rate
// TODO add some logic for when there's no data and we get a timeout
while (idx < sizeof(answerFrame)) {
if(RS485Serial.available()) {
byteReceived = RS485Serial.read();
// Serial.println(byteReceived, HEX);
answerFrame[idx] = byteReceived;
idx++;
}
}
// Print out answer bytes
/*
Byte 0: sensor address
Byte 1: Function code
Byte 2: valid bytes (2 valid bytes per read variable)
Byte 3+4: 1st read variable
Byte 5+6: 2nd read variable
Byte n-1 + n: CRC checks
*/
Serial.println(" ");
Serial.println("Answer bytes:");
for(int i = 0; i < sizeof(answerFrame); i++){
Serial.print(answerFrame[i], HEX);
Serial.print(" ");
}
Serial.println();
Serial.println();
Serial.print("Sensor number: ");
Serial.println(answerFrame[0], HEX);
Serial.print("Number of read variables: ");
Serial.println(answerFrame[2] / 2, DEC);
vwc = word(answerFrame[3], answerFrame[4]); // word = 2 bytes, high byte first
Serial.print("vwc: ");
Serial.println(vwc / 10 , DEC);
temp = word(answerFrame[5], answerFrame[6]);
Serial.print("soil T: ");
Serial.println(temp / 10, DEC);
Serial.println(" ");
// Get reading every 5 seconds
delay(5000);
/* TODO add a CRC check for the received data, i.e. take n-2 bytes of the answer,
calculate CRC, and then compare if it fist with the CRC bytes that were received.
*/
}
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:esp32-c3-devkitm-1]
platform = espressif32
board = esp32-c3-devkitm-1
framework = arduino
monitor_speed = 115000
lib_deps = EspSoftwareSerial
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment