//#define XPT2046
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#include <Adafruit_ADS1X15.h>
#include <Adafruit_MCP23X17.h>
#ifdef XPT2046
#include <XPT2046_Touchscreen.h>
#else
#include <Adafruit_FT6206.h>
#endif
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <FS.h>
#include <SD.h>
#include <time.h>
#include <Wire.h>
// ====================== PIN DEFINITIONS ======================
#define TFT_CS 15
#define TFT_DC 2
#define TFT_MOSI 13
#define TFT_MISO 12
#define TFT_SCK 14
#define TFT_BL 21
#ifdef XPT2046
#define XPT2046_CS 33
#define XPT2046_IRQ 36
#define XPT2046_MOSI 32
#define XPT2046_MISO 39
#define XPT2046_CLK 25
#endif
#define SD_CS_PIN 5
#define SD_SCK 18
#define SD_MISO 19
#define SD_MOSI 23
#define LED_R 17
#define LED_G 16
#define LED_B 4
#define I2C_SDA 27
#define I2C_SCL 22
// ====================== OBJECTS ======================
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
SPIClass sdSPI(HSPI);
#ifdef XPT2046
SPIClass touchSPI(VSPI);
XPT2046_Touchscreen touchscreen(XPT2046_CS, XPT2046_IRQ);
#endif
Adafruit_ADS1115 ads; // <-- Fixed: no address here
Adafruit_MCP23X17 mcp;
AsyncWebServer server(80);
// =================== Touch Screen =====================
// The FT6206 uses hardware I2C (SCL/SDA)
Adafruit_FT6206 ts = Adafruit_FT6206();
boolean RecordOn = false;
#define FRAME_X 210
#define FRAME_Y 180
#define FRAME_W 100
#define FRAME_H 50
#define REDBUTTON_X FRAME_X
#define REDBUTTON_Y FRAME_Y
#define REDBUTTON_W (FRAME_W/2)
#define REDBUTTON_H FRAME_H
#define GREENBUTTON_X (REDBUTTON_X + REDBUTTON_W)
#define GREENBUTTON_Y FRAME_Y
#define GREENBUTTON_W (FRAME_W/2)
#define GREENBUTTON_H FRAME_H
void init_ts() {
if (!ts.begin(40)) {
Serial.println("Unable to start touchscreen.");
} else {
Serial.println("started touchscreen.");
}
}
void drawFrame() {
tft.drawRect(FRAME_X, FRAME_Y, FRAME_W, FRAME_H, ILI9341_BLACK);
}
void redBtn() {
tft.fillRect(REDBUTTON_X, REDBUTTON_Y, REDBUTTON_W, REDBUTTON_H, ILI9341_RED);
tft.fillRect(GREENBUTTON_X, GREENBUTTON_Y, GREENBUTTON_W, GREENBUTTON_H, ILI9341_BLUE);
drawFrame();
tft.setCursor(GREENBUTTON_X + 6, GREENBUTTON_Y + (GREENBUTTON_H / 2));
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(2);
tft.println("ON");
RecordOn = false;
}
void greenBtn() {
tft.fillRect(GREENBUTTON_X, GREENBUTTON_Y, GREENBUTTON_W, GREENBUTTON_H, ILI9341_GREEN);
tft.fillRect(REDBUTTON_X, REDBUTTON_Y, REDBUTTON_W, REDBUTTON_H, ILI9341_BLUE);
drawFrame();
tft.setCursor(REDBUTTON_X + 6, REDBUTTON_Y + (REDBUTTON_H / 2));
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(2);
tft.println("OFF");
RecordOn = true;
}
// ====================== VARIABLES ======================
const char *ssid = "Wokwi-GUEST";
const char *password = "";
String date_time;
unsigned long lastLogTime = 0;
const unsigned long logInterval = 5000;
int16_t prev_adc0 = -9999, prev_adc1 = -9999, prev_adc2 = -9999, prev_adc3 = -9999;
// ====================== HELPERS ======================
void setRGB(byte r, byte g, byte b) {
analogWrite(LED_R, r);
analogWrite(LED_G, g);
analogWrite(LED_B, b);
/*
digitalWrite(LED_R, r ? LOW : HIGH);
digitalWrite(LED_G, g ? LOW : HIGH);
digitalWrite(LED_B, b ? LOW : HIGH);
*/
}
float mapFloat(float x, float in_min, float in_max, float out_min, float out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
void getTime() {
struct tm timeinfo;
if (getLocalTime(&timeinfo)) {
date_time = String(timeinfo.tm_year + 1900) + "/" +
String(timeinfo.tm_mon + 1) + "/" +
String(timeinfo.tm_mday) + "," +
String(timeinfo.tm_hour) + ":" + String(timeinfo.tm_min);
}
}
/*
void appendFile(fs::FS &fs, const char *path, const char *message) {
File file = fs.open(path, FILE_APPEND);
if (file) {
file.print(message);
file.close();
}
}
*/
void displayReadings(float v0, float v1, float v2, float v3, float p) {
tft.fillScreen(ILI9341_BLACK);
tft.setCursor(0, 0);
tft.setTextSize(2);
tft.setTextColor(ILI9341_WHITE);
tft.printf("V0: %.3f\n", v0);
tft.printf("V1: %.3f\n", v1);
tft.printf("V2: %.3f\n", v2);
tft.printf("V3: %.3f\n", v3);
tft.printf("PSI: %.2f\n", p);
}
//======================================================================
// Write to the SD card
void writeFile(fs::FS &fs, const char *path, const char *message) {
//Serial.printf("Writing file: %s\n", path);
File file = fs.open(path, FILE_WRITE);
if (!file) {
Serial.println("Failed to open file for writing");
return;
}
if (file.print(message)) {
//Serial.println("File written");
} else {
Serial.println("Write failed");
}
file.close();
}
//======================================================================
// Append data to the SD card
void appendFile(fs::FS &fs, const char *path, const char *message) {
//Serial.printf("Appending to file: %s\n", path);
File file = fs.open(path, FILE_APPEND);
if (!file) {
Serial.println("Failed to open file for appending");
delay(1000);
return;
}
if (file.print(message)) {
//Serial.println("Message appended");
} else {
Serial.println("Append failed");
delay(1000);
}
file.close();
}
//======================================================================
// Delete file
void deleteFile(fs::FS &fs, const char *path) {
Serial.printf("Deleting file: %s\r\n", path);
if (fs.remove(path)) {
Serial.println("- file deleted");
} else {
Serial.println("- delete failed");
}
}
// ====================== SETUP ======================
void setup() {
Serial.begin(115200);
delay(2000);
Serial.println("\n=== CYD Logger Starting ===");
Wire.begin(I2C_SDA, I2C_SCL);
scan_i2c();
pinMode(LED_R, OUTPUT);
pinMode(LED_G, OUTPUT);
pinMode(LED_B, OUTPUT);
setRGB(1, 0, 0);
delay(1000);
setRGB(0, 1, 0);
delay(1000);
setRGB(0, 0, 1);
delay(1000);
setRGB(0, 0, 0);
delay(1000);
// Display
pinMode(TFT_BL, OUTPUT);
digitalWrite(TFT_BL, HIGH);
SPI.begin(TFT_SCK, TFT_MISO, TFT_MOSI, TFT_CS);
tft.begin();
tft.setRotation(3);
tft.fillScreen(ILI9341_BLACK);
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(2);
tft.println("Starting...");
// SD Card
sdSPI.begin(SD_SCK, SD_MISO, SD_MOSI, SD_CS_PIN);
if (!SD.begin(SD_CS_PIN, sdSPI)) {
Serial.println("SD Mount Failed!");
} else {
Serial.println("SD OK");
}
// If the logs.txt file doesn't exist
// Create a file on the SD card and write the data labels
File file = SD.open("/logs.txt");
if (!file) {
Serial.println("File doesn't exist");
delay(500);
Serial.println("Creating file...");
writeFile(SD, "/logs.txt", "Date, Time, volt0, bar0 , psi0 , volt1, volt2, volt3 \r\n");
} else {
Serial.println("File already exists");
}
file.close();
// MCP23017
if (!mcp.begin_I2C(0x20, &Wire)) {
Serial.println("MCP Failed");
} else {
Serial.println("MCP OK");
}
// ADS1115
ads.setGain(GAIN_TWOTHIRDS);
if (!ads.begin()) { // Default address 0x48
Serial.println("ADS1115 Failed");
} else {
Serial.println("ADS1115 OK");
}
#ifdef XPT2046
// Touch
touchSPI.begin(XPT2046_CLK, XPT2046_MISO, XPT2046_MOSI, XPT2046_CS);
touchscreen.begin(touchSPI);
touchscreen.setRotation(1);
#else
init_ts();
#endif
/*
// Time
setenv("TZ", "CST6CDT,M3.2.0,M11.1.0", 1);
tzset();
configTime(0, 0, "pool.ntp.org");
// WiFi
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi OK - IP: " + WiFi.localIP().toString());
// Web Server
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send(SD, "/index.html", "text/html");
});
server.on("/download", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send(SD, "/logs.txt", String(), true);
});
server.on("/delete", HTTP_GET, [](AsyncWebServerRequest *request) {
SD.remove("/logs.txt");
request->send(200, "text/plain", "Deleted");
});
server.begin();
*/
// Create log file if missing
if (!SD.exists("/logs.txt")) {
File f = SD.open("/logs.txt", FILE_WRITE);
if (f) {
f.println("Date,Time,V0,Pressure,PSI,V1,V2,V3");
f.close();
}
}
setRGB(0, 1, 0);
Serial.println("=== Ready ===\n");
}
// ====================== LOOP ======================
void loop() {
#ifdef XPT2046
// Touch
if (touchscreen.tirqTouched() && touchscreen.touched()) {
TS_Point p = touchscreen.getPoint();
int x = map(p.x, 200, 3700, 0, 320);
int y = map(p.y, 240, 3800, 0, 240);
Serial.printf("Touch -> X=%d Y=%d\n", x, y);
}
#else
#endif
// Periodic Logging
if (millis() - lastLogTime >= logInterval) {
int16_t adc0 = ads.readADC_SingleEnded(0);
int16_t adc1 = ads.readADC_SingleEnded(1);
int16_t adc2 = ads.readADC_SingleEnded(2);
int16_t adc3 = ads.readADC_SingleEnded(3);
float v0 = ads.computeVolts(adc0);
float v1 = ads.computeVolts(adc1);
float v2 = ads.computeVolts(adc2);
float v3 = ads.computeVolts(adc3);
float pressure = mapFloat(v0, 0.02, 5.0, 0.0, 10.0);
float psi = pressure * 14.5038;
getTime();
// Log on change
if (abs(adc0 - prev_adc0) > 8 || abs(adc1 - prev_adc1) > 8 ||
abs(adc2 - prev_adc2) > 8 || abs(adc3 - prev_adc3) > 8) {
String data = date_time + "," +
String(v0, 3) + "," + String(pressure, 3) + "," +
String(psi, 3) + "," + String(v1, 3) + "," +
String(v2, 3) + "," + String(v3, 3) + "\r\n";
Serial.print(data);
appendFile(SD, "/logs.txt", data.c_str());
displayReadings(v0, v1, v2, v3, psi);
prev_adc0 = adc0;
prev_adc1 = adc1;
prev_adc2 = adc2;
prev_adc3 = adc3;
}
lastLogTime = millis();
}
delay(10);
}address 0x20
address 0x48
1
8
9
16
address 0x68
address 0x38
address 0x50