#include <SPI.h>
#include <SD.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h> // 1.8" TFT
#include <Encoder.h>
// TFT & SD
#define TFT_CS 10
#define TFT_DC 9
#define TFT_RST 8
#define SD_CS 4
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
// Relay pinlari
#define RELAY1 22 // Pump1
#define RELAY2 23 // Pump2
#define RELAY3 24 // Pump3
#define RELAY4 25 // Pump4 (output)
#define RELAY5 26 // Mixing motor
// Encoder
#define ENC_A 2
#define ENC_B 3
#define ENC_BTN 7
Encoder myEnc(ENC_A, ENC_B);
long oldPosition = -999;
int menuIndex = 0;
String menuItems[] = {"Fayl tanlash", "Start", "Stop", "Pump Test", "Motor Test"};
int totalMenu = 5;
// Recipe
File recipeFile;
int recipe[4] = {0,0,0,0}; // 4 ta nasos uchun
bool recipeLoaded = false;
bool running = false;
void setup() {
Serial.begin(9600);
// TFT
tft.initR(INITR_BLACKTAB);
tft.fillScreen(ST77XX_BLACK);
tft.setTextColor(ST77XX_WHITE);
tft.setTextSize(1);
tft.setCursor(10, 10);
tft.println("Qurilma start...");
// SD init
if (!SD.begin(SD_CS)) {
tft.println("SD error!");
while (1);
}
tft.println("SD OK");
// Relay chiqishlar
pinMode(RELAY1, OUTPUT);
pinMode(RELAY2, OUTPUT);
pinMode(RELAY3, OUTPUT);
pinMode(RELAY4, OUTPUT);
pinMode(RELAY5, OUTPUT);
digitalWrite(RELAY1, LOW);
digitalWrite(RELAY2, LOW);
digitalWrite(RELAY3, LOW);
digitalWrite(RELAY4, LOW);
digitalWrite(RELAY5, LOW);
pinMode(ENC_BTN, INPUT_PULLUP);
drawMenu();
}
// ====================== MENU DRAW =======================
void drawMenu() {
tft.fillScreen(ST77XX_BLACK);
for (int i=0; i<totalMenu; i++) {
if (i == menuIndex) {
tft.setTextColor(ST77XX_YELLOW);
} else {
tft.setTextColor(ST77XX_WHITE);
}
tft.setCursor(10, 20 + i*15);
tft.println(menuItems[i]);
}
}
// ====================== LOAD RECIPE =====================
void loadRecipe(const char *filename) {
recipeFile = SD.open(filename);
if (recipeFile) {
String line = recipeFile.readStringUntil('\n');
recipeFile.close();
int i = 0;
char *token = strtok((char*)line.c_str(), ",");
while (token != NULL && i<4) {
recipe[i] = atoi(token);
token = strtok(NULL, ",");
i++;
}
recipeLoaded = true;
tft.fillScreen(ST77XX_BLACK);
tft.setCursor(10, 20);
tft.setTextColor(ST77XX_GREEN);
tft.println("Recipe yuklandi!");
} else {
tft.println("Fayl topilmadi!");
}
}
// ====================== RUN RECIPE =====================
void runRecipe() {
if (!recipeLoaded) return;
for (int i=0; i<4; i++) {
if (recipe[i] > 0) {
int ms = (recipe[i] * 600); // 100 ml/min = 600 ms har ml uchun
digitalWrite(RELAY1+i, HIGH);
delay(ms);
digitalWrite(RELAY1+i, LOW);
}
}
// Mixing motor
digitalWrite(RELAY5, HIGH);
delay(5000);
digitalWrite(RELAY5, LOW);
tft.fillScreen(ST77XX_BLACK);
tft.setCursor(10, 20);
tft.setTextColor(ST77XX_GREEN);
tft.println("Recipe tugadi!");
}
// ====================== LOOP ===========================
void loop() {
long newPosition = myEnc.read() / 4;
if (newPosition != oldPosition) {
oldPosition = newPosition;
menuIndex = (newPosition % totalMenu + totalMenu) % totalMenu;
drawMenu();
}
if (digitalRead(ENC_BTN) == LOW) {
delay(200);
switch(menuIndex) {
case 0: loadRecipe("recipe1.txt"); break;
case 1: runRecipe(); break;
case 2: running = false; break;
case 3: digitalWrite(RELAY1, HIGH); delay(2000); digitalWrite(RELAY1, LOW); break;
case 4: digitalWrite(RELAY5, HIGH); delay(2000); digitalWrite(RELAY5, LOW); break;
}
}
}