ATmega2560 + ST7735 — Smart Display Controller for Irrigation RelaysATmega2560 + ST7735 — Smart Display Controller for Irrigation Relays

ATmega2560 + ST7735 — Smart Display Controller for Irrigation Relays

Building a display‑driven controller around the ATmega2560 is an excellent way to create a reliable and extensible automation system.
In this project, we focus on using an ST7735 TFT display to visualize sensor values, irrigation line names, tolerance thresholds, and relay states.
The goal is to keep the code modular, readable, and ready for future expansion, while staying faithful to your original snippet.

This MDX file contains everything in one place: explanation, architecture, and a fully commented sketch.
The code is based strictly on your provided prototype, with unnecessary parts removed and the logic reorganized for clarity.


🧩 Project Overview

This controller is designed for:

  • Four irrigation lines, each with its own relay
  • A tank level sensor connected to a digital input
  • An ST7735 TFT display used to show live data
  • Reference values, tolerances, and crop names for each line
  • Expandable SPI infrastructure (kept from your snippet)

The ATmega2560 is ideal for this because of its abundant I/O pins and stable hardware timers.


🔌 Hardware Components

  • ATmega2560 board (Arduino Mega 2560 or compatible)
  • ST7735 TFT display (SPI, 160px width)
  • 4 relay modules (active‑low)
  • 1 level sensor (float switch or capacitive probe)
  • Optional: SD card module (your snippet already includes SdFat structures)

🧠 Data Model

Your original snippet already defines a clean structure:

  • valore_letto[] → current sensor readings
  • valore_rif[] → reference values
  • tolleranza[] → allowed deviation
  • coltivazione[] → crop names
  • linea[] → irrigation line labels

This makes it easy to build a UI on the ST7735.


🖥️ Full ATmega2560 + ST7735 Code (cleaned, improved, commented)

Below is the complete sketch, rewritten for clarity but using ONLY your provided code as the base.

irrigatore.ccp
// Software SPI driver instance (kept from your snippet)
SoftSpiDriver<SOFT_MISO_PIN, SOFT_MOSI_PIN, SOFT_SCK_PIN> softSpi;
// SPI configuration for SdFat (kept for future SD logging)
SdSpiConfig spiConfig(CS_PIN, SHARED_SPI, SD_SCK_MHZ(4), &softSpi);
// SdFat objects (not used directly here, but ready for expansion)
SdFat sd;
File file;
// Maximum number of stored readings
const int maxRighe = 200;
int dati[4][maxRighe];
int numRighe = 0;
#define LARGHEZZA_DISPLAY 160
// Relay pins for pumps
const int pin_p_1 = 38;
const int pin_p_2 = 39;
const int pin_p_3 = 40;
const int pin_p_4 = 41;
const int relayPins[] = {38, 39, 40, 41};
// Level sensor pin
const int livelloPin = 2;
unsigned long backlightStartTime = 0;
bool backlightOn = false;
// Example sensor values
int valore_letto[] = {100,108,103,110};
int valore_rif[4];
String coltivazione[4];
int tolleranza[4];
String linea[]= {"Linea 1", "Linea 2", "Linea 3", "Linea 4"};
// ST7735 display instance
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
// Draw a single irrigation line status on the TFT
void drawLineStatus(uint8_t index, int y) {
if (index >= 4) return;
int current = valore_letto[index];
int target = valore_rif[index];
int delta = current - target;
bool inRange = abs(delta) <= tolleranza[index];
uint16_t color = inRange ? ST77XX_GREEN : ST77XX_RED;
// Clear the row
tft.fillRect(0, y, LARGHEZZA_DISPLAY, 18, ST77XX_BLACK);
// Line name + crop
tft.setCursor(2, y + 2);
tft.setTextColor(ST77XX_WHITE);
tft.print(linea[index]);
tft.print(" - ");
tft.print(coltivazione[index]);
// Value + target
tft.setCursor(2, y + 10);
tft.setTextColor(color);
tft.print("Val: ");
tft.print(current);
tft.print(" (T: ");
tft.print(target);
tft.print(")");
}
void setup() {
Serial.begin(115200);
// Initialize relays
for (int i = 0; i < 4; i++) {
pinMode(relayPins[i], OUTPUT);
digitalWrite(relayPins[i], HIGH); // OFF at startup
}
// Level sensor
pinMode(livelloPin, INPUT_PULLUP);
// Display setup
tft.initR(INITR_BLACKTAB);
tft.fillScreen(ST77XX_BLACK);
tft.setRotation(1);
tft.setTextColor(ST77XX_WHITE);
tft.setTextSize(1);
// Welcome screen
tft.setCursor(5, 10);
tft.println("Irrigation Controller");
tft.setCursor(5, 30);
tft.println("ATmega2560 + ST7735");
delay(1200);
tft.fillScreen(ST77XX_BLACK);
// Initialize metadata
coltivazione[0] = "Chocolate";
coltivazione[1] = "Yellow";
coltivazione[2] = "Origano";
coltivazione[3] = "Salvia";
valore_rif[0] = 150;
valore_rif[1] = 130;
valore_rif[2] = 160;
valore_rif[3] = 80;
tolleranza[0] = 5;
tolleranza[1] = 3;
tolleranza[2] = 6;
tolleranza[3] = 8;
}
void loop() {
// Simulate sensor drift (replace with real analogRead)
for (int i = 0; i < 4; i++) {
valore_letto[i] += random(-2, 3);
}
bool tankOk = (digitalRead(livelloPin) == LOW);
// Header
tft.fillRect(0, 0, LARGHEZZA_DISPLAY, 16, ST77XX_BLACK);
tft.setCursor(2, 2);
tft.setTextColor(ST77XX_CYAN);
tft.print("Tank: ");
tft.print(tankOk ? "OK" : "LOW");
// Draw each line
drawLineStatus(0, 18);
drawLineStatus(1, 40);
drawLineStatus(2, 62);
drawLineStatus(3, 84);
// Relay logic
for (int i = 0; i < 4; i++) {
bool needWater = valore_letto[i] < valore_rif[i];
if (tankOk && needWater) {
digitalWrite(relayPins[i], LOW); // ON
} else {
digitalWrite(relayPins[i], HIGH); // OFF
}
}
delay(500);
}

← Back to projects