#include <Arduino.h>
#include <Wire.h>
#include <max6675.h>
#include <RTClib.h>
// -----------------------------------------------------------------------------------------
// HARDWARE PINS
// -----------------------------------------------------------------------------------------
// MAX6675 Thermocouple
#define MAX6675_SCK 18
#define MAX6675_CS 5
#define MAX6675_SO 19
MAX6675 thermocouple(MAX6675_SCK, MAX6675_CS, MAX6675_SO);
// DWIN UART2
#define DWIN_RX 25
#define DWIN_TX 26
#define DWIN_SERIAL Serial2
// External Real-Time Clock
RTC_DS3231 rtc;
bool rtcFound = false;
// -----------------------------------------------------------------------------------------
// DWIN VARIABLE POINTERS (VPs)
// -----------------------------------------------------------------------------------------
const uint16_t TEMP_VP = 0x1000; // Temperature Display (Numeric 2 Digits)
const uint16_t DATE_VP = 0x1010; // Date Display (Text Display, Length 12)
const uint16_t TIME_VP = 0x1020; // Time Display (Text Display, Length 10)
// Update timing
unsigned long lastUpdate = 0;
const unsigned long UPDATE_INTERVAL = 1000; // Update display every 1 second
// Software Clock Fallback (used if physical RTC is disconnected)
uint16_t softYear = 2026;
uint8_t softMonth = 10;
uint8_t softDay = 2;
uint8_t softHour = 20;
uint8_t softMinute = 20;
uint8_t softSecond = 0;
// -----------------------------------------------------------------------------------------
// DWIN PROTOCOL HELPERS
// -----------------------------------------------------------------------------------------
// Send 16-bit integer to DWIN numeric VP
void sendDwinWord(uint16_t address, uint16_t value) {
byte pkt[8];
pkt[0] = 0x5A;
pkt[1] = 0xA5;
pkt[2] = 0x05;
pkt[3] = 0x82; // Write Command
pkt[4] = highByte(address);
pkt[5] = lowByte(address);
pkt[6] = highByte(value);
pkt[7] = lowByte(value);
DWIN_SERIAL.write(pkt, 8);
DWIN_SERIAL.flush();
}
// Send ASCII text string to DWIN Text Display with dual 0xFF terminator
void sendDwinString(uint16_t address, String text, int maxLen = 12) {
byte pkt[36];
byte payloadLen = 3 + maxLen; // 0x82 + vpH + vpL + maxLen
pkt[0] = 0x5A;
pkt[1] = 0xA5;
pkt[2] = payloadLen;
pkt[3] = 0x82; // Write Command
pkt[4] = highByte(address);
pkt[5] = lowByte(address);
int textLen = text.length();
for (int i = 0; i < maxLen; i++) {
if (i < textLen) {
pkt\[6 + i\] = (byte)text\[i\];
} else if (i == textLen || i == textLen + 1) {
pkt\[6 + i\] = 0xFF; // DWIN standard string terminator
} else {
pkt\[6 + i\] = 0x00;
}
}
DWIN_SERIAL.write(pkt, 3 + payloadLen);
DWIN_SERIAL.flush();
}
// -----------------------------------------------------------------------------------------
// SOFTWARE CLOCK TICKER (Fallback if physical RTC disconnects)
// -----------------------------------------------------------------------------------------
void tickSoftwareClock() {
softSecond++;
if (softSecond >= 60) {
softSecond = 0;
softMinute++;
if (softMinute >= 60) {
softMinute = 0;
softHour++;
if (softHour >= 24) {
softHour = 0;
softDay++;
}
}
}
}
// -----------------------------------------------------------------------------------------
// SETUP
// -----------------------------------------------------------------------------------------
void setup() {
Serial.begin(115200);
// Initialize I2C for External RTC (SDA=21, SCL=22)
Wire.begin(21, 22);
// Start DWIN hardware serial communication (UART2)
DWIN_SERIAL.begin(115200, SERIAL_8N1, DWIN_RX, DWIN_TX);
// Cold-boot delay: Give DWIN screen 2 seconds to complete power-on self-test
delay(2000);
Serial.println("\n=======================================================");
Serial.println(" ESP32 TEMPERATURE, DATE & TIME RECORDER CONTROLLER ");
Serial.println("=======================================================");
// Initialize External RTC
if (rtc.begin()) {
rtcFound = true;
Serial.println("\[RTC\] External Hardware RTC detected on I2C (GPIO 21/22)!");
if (rtc.lostPower()) {
Serial.println("\[RTC\] Battery was disconnected, setting to compile time.");
rtc.adjust(DateTime(F(\__DATE_\_), F(\__TIME_\_)));
}
} else {
rtcFound = false;
Serial.println("\[RTC\] Warning: No external RTC detected. Running software clock.");
}
}
// -----------------------------------------------------------------------------------------
// MAIN LOOP
// -----------------------------------------------------------------------------------------
void loop() {
unsigned long now = millis();
// Execute update every 1 second
if (now - lastUpdate >= UPDATE_INTERVAL) {
lastUpdate = now;
// =========================================================
// 1. READ & DISPLAY TEMPERATURE (MAX6675)
// =========================================================
float tempC = thermocouple.readCelsius();
if (isnan(tempC)) {
Serial.println("\[ERROR\] Thermocouple disconnected or reading failed!");
sendDwinWord(TEMP_VP, 0);
} else {
Serial.printf("\[TEMP\] Sensor Output: %.1f °C\\n", tempC);
// Warning diagnostic for reversed thermocouple polarity
if (tempC >= 5.0 && tempC <= 16.0) {
Serial.println(">>> \[NOTICE\] Reading 8-13°C at room temperature indicates REVERSED WIRES!");
Serial.println(">>> Please swap the (+) and (-) wires on the MAX6675 screw terminal.");
}
// Send whole integer (e.g. 26 °C) to fit 2-digit display
uint16_t dwinIntVal = (uint16_t)round(tempC);
sendDwinWord(TEMP_VP, dwinIntVal);
}
// =========================================================
// 2. READ & FORMAT DATE AND TIME FROM EXTERNAL RTC
// =========================================================
uint16_t year;
uint8_t month, day, hour, minute, second;
if (rtcFound) {
DateTime dt = rtc.now();
year = dt.year();
month = dt.month();
day = dt.day();
hour = dt.hour();
minute = dt.minute();
second = dt.second();
} else {
tickSoftwareClock();
year = softYear;
month = softMonth;
day = softDay;
hour = softHour;
minute = softMinute;
second = softSecond;
}
// Format Date String: "DD-MM-YYYY" (10 chars, fits 12-byte VP 0x1010)
char dateBuf\[12\];
snprintf(dateBuf, sizeof(dateBuf), "%02d-%02d-%04d", day, month, year);
// Format Time String: "HH:MM:SS" (8 chars, fits 10-byte VP 0x1020)
char timeBuf\[10\];
snprintf(timeBuf, sizeof(timeBuf), "%02d:%02d:%02d", hour, minute, second);
Serial.printf("\[CLOCK\] Date: %s | Time: %s\\n", dateBuf, timeBuf);
// =========================================================
// 3. SEND DATE & TIME TO DWIN SCREEN
// =========================================================
sendDwinString(DATE_VP, String(dateBuf), 12);
delay(5);
sendDwinString(TIME_VP, String(timeBuf), 10);
}
}Use code tags to format code for the forum