#include <LiquidCrystal_I2C.h>
#define I2C_ADDR 0x27
#define LCD_COLUMNS 20
#define LCD_LINES 4
int started = 0;
LiquidCrystal_I2C lcd(I2C_ADDR, LCD_COLUMNS, LCD_LINES);
// Constants
#define MAX485_PIN 5 // PIN to control MAX485 direction
#define SLAVE_ID 1
#define MODBUS_TIMEOUT 1000
// Modbus function codes
#define READ_HOLDING_REGISTERS 0x03
#define WRITE_SINGLE_REGISTER 0x06
// Register addresses
#define TEMP_REG 0x00
#define HUM_REG 0x01
#define RELAY1_REG 0x02
#define RELAY2_REG 0x03
uint8_t humheatdata[9];
uint8_t crdone[8];
char placeholder[10];
// CRC calculation function
uint16_t calculateCRC(uint8_t* buffer, int length) {
uint16_t crc = 0xFFFF;
for (int pos = 0; pos < length; pos++) {
crc ^= (uint16_t)buffer[pos];
for (int i = 8; i != 0; i--) {
if ((crc & 0x0001) != 0) {
crc >>= 1;
crc ^= 0xA001;
} else {
crc >>= 1;
}
}
}
return crc;
}
void sendModbusRequest(uint8_t* request, int length) {
digitalWrite(MAX485_PIN, HIGH); // Set MAX485 to transmit mode
delay(10);
Serial.write(request, length);
Serial.flush();
digitalWrite(MAX485_PIN, LOW); // Set MAX485 to receive mode
}
void readSensorData() {
uint8_t request[8] = {
SLAVE_ID,
READ_HOLDING_REGISTERS,
0x00, // Starting address high byte
0x00, // Starting address low byte
0x00, // Number of registers high byte
0x02 // Number of registers low byte (reading 2 registers)
};
uint16_t crc = calculateCRC(request, 6);
request[6] = crc & 0xFF;
request[7] = (crc >> 8) & 0xFF;
if (started == 0){delay(4000); started = 1;}
sendModbusRequest(request, 8);
// Wait for response
while (Serial.available() < 9) {delay(20);}; // Minimum request length
Serial.readBytes(humheatdata, 9);
uint16_t receivedCRC = (humheatdata[8] << 8) | humheatdata[7];
uint16_t calculatedCRC = calculateCRC(humheatdata, 7);
while (receivedCRC != calculatedCRC) {Serial.println("qerror");};
}
void controlRelay(uint8_t relay, bool state) {
uint8_t request[8] = {
SLAVE_ID,
WRITE_SINGLE_REGISTER,
0x00,
(relay == 0) ? RELAY1_REG : RELAY2_REG, // Register address
0x00,
state ? 0x01 : 0x00 // Value to write
};
uint16_t crc = calculateCRC(request, 6);
request[6] = crc & 0xFF;
request[7] = (crc >> 8) & 0xFF;
sendModbusRequest(request, 8);
while (Serial.available() < 8) {delay(20);}; // Minimum request length
Serial.readBytes(crdone, 8);
lcd.setCursor(0, 0);
lcd.print(crdone[0]);
lcd.setCursor(4, 0);
lcd.print(crdone[1]);
lcd.setCursor(8, 0);
lcd.print(crdone[2]);
lcd.setCursor(0, 1);
lcd.print(crdone[3]);
lcd.setCursor(4, 1);
lcd.print(crdone[4]);
lcd.setCursor(8, 1);
lcd.print(crdone[5]);
lcd.setCursor(0, 2);
lcd.print(crdone[6]);
lcd.setCursor(4, 2);
lcd.print(crdone[7]);
uint16_t receivedCRC = (humheatdata[8] << 8) | humheatdata[7];
uint16_t calculatedCRC = calculateCRC(humheatdata, 7);
while (receivedCRC != calculatedCRC) {Serial.println("error");};
}
void setup() {
// Init
lcd.init();
lcd.backlight();
Serial.begin(9600);
pinMode(MAX485_PIN, OUTPUT);
digitalWrite(MAX485_PIN, LOW); // Start in receive mode
}
void loop() {
readSensorData();
delay(100); // Read every .1 seconds
int16_t temperature = (humheatdata[3] << 8) | humheatdata[4];
int16_t humidity = (humheatdata[5] << 8) |humheatdata[6];
// Example: Toggle relays based on some condition
if (temperature < 20) {controlRelay(0, true);}
if (temperature > 25) {controlRelay(0, false);}
if (humidity < 30) {controlRelay(1, true);}
if (humidity > 50) {controlRelay(1, false);}
}