#include "SPI.h"
#include <Wire.h>
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
#include <Adafruit_FT6206.h>
#include <DS1307RTC.h>
// The FT6206 uses hardware I2C (SCL/SDA)
Adafruit_FT6206 ctp = Adafruit_FT6206();
// Definisi area touch sebagai tombol
#define BUTTON_UP_X 0
#define BUTTON_UP_Y 285
#define BUTTON_UP_W 36
#define BUTTON_UP_H 35
#define BUTTON_DOWN_X 44
#define BUTTON_DOWN_Y 285
#define BUTTON_DOWN_W 36
#define BUTTON_DOWN_H 35
#define BUTTON_TIME_X 88
#define BUTTON_TIME_Y 285
#define BUTTON_TIME_W 45
#define BUTTON_TIME_H 35
#define BUTTON_ALARM_X 141
#define BUTTON_ALARM_Y 285
#define BUTTON_ALARM_W 45
#define BUTTON_ALARM_H 35
#define BUTTON_GMT_X 194
#define BUTTON_GMT_Y 285
#define BUTTON_GMT_W 45
#define BUTTON_GMT_H 35
#define TFT_DC 9
#define TFT_CS 10
bool isTouchInArea(int16_t tx, int16_t ty, int16_t x, int16_t y, int16_t w, int16_t h) {
return (tx >= x && tx <= (x + w) && ty >= y && ty <= (y + h));
}
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
#define ILI9341_GREY 0x5AEB
float sx = 0, sy = 1, mx = 1, my = 0, hx = -1, hy = 0; // Saved H, M, S x & y multipliers
float sdeg=0, mdeg=0, hdeg=0;
uint16_t center = 20;
uint16_t osx=120, osy=120+center, omx=120, omy=120+center, ohx=120, ohy=120+center; // Saved H, M, S x & y coords
uint16_t x0=0, x1=0, y0=0, y1=0;
uint32_t PreviousMillis;
uint8_t hh, mm, ss;
String dateStr;
boolean initial = 1;
String GMTT; //untuk mengubah tampilan GMT+7
bool relay=false; //untuk fungsi relay saat ON dan OFF
int GMT=7; //untuk membuat default GMT=+7
int rh=0; //revisi hour(untuk pengubahan jam pada menu time)
int rm=0; //revisi minute(untuk pengubahan menit pada menu time)
int rma=0; //minute alarm untuk alarm, default 0
int rha=0; //hour alarm untuk alarm, default 0
int rtch; //untuk pembacaan hour pada rtc
int rtcm; //untuk pembacaan minute pada rtc
int rtcs; //untuk pembacaan second pada rtc
int pagetime=0; //page untuk menu time
int pagealarm=0; //page untuk menu alarm
int pageGMT=0; //page untuk menu GMT
bool running = true; //untuk membuat RTC berjalan
bool ss0 = false; //untuk membuat detik menjadi 0 ketika selesai atur alarm
bool hold = false; //untuk menahan relay tetap off ketika selesai atur alarm
void setup(void) {
Serial.begin(115200);
Serial.println(F("Cap Touch Paint!"));
tft.begin();
if (! ctp.begin(40)) { // pass in 'sensitivity' coefficient
Serial.println("Couldn't start FT6206 touchscreen controller");
while (1);
}
Serial.println("Capacitive touchscreen started");
tft.setRotation(0);
tft.fillScreen(ILI9341_GREY);
tft.setTextColor(ILI9341_CYAN, ILI9341_GREY); // Adding a background colour erases previous text automatically
drawCenterString("Jam Analog", 2, 2, ILI9341_CYAN);
// Draw clock face
tft.fillCircle(120, 120+center, 118, ILI9341_BLUE);
tft.fillCircle(120, 120+center, 110, ILI9341_BLACK);
// Draw 12 lines
for(int i = 0; i<360; i+= 30) {
sx = cos((i-90)*0.0174532925);
sy = sin((i-90)*0.0174532925);
x0 = sx*110+120;
y0 = sy*110+120+center;
x1 = sx*102+120;
y1 = sy*102+120+center;
tft.drawLine(x0, y0, x1, y1, ILI9341_CYAN);
}
printHourText();
// Draw 60 dots
for(int i = 0; i<360; i+= 6) {
sx = cos((i-90)*0.0174532925);
sy = sin((i-90)*0.0174532925);
x0 = sx*102+120;
y0 = sy*102+120+center;
// Draw minute markers
tft.drawPixel(x0, y0, ILI9341_WHITE);
// Draw main quadrant dots
if(i==0 || i==180) tft.fillCircle(x0, y0, 4, ILI9341_YELLOW);
if(i==90 || i==270) tft.fillCircle(x0, y0, 4, ILI9341_YELLOW);
}
printHourText();
// Draw touch Screen Button
tft.fillRoundRect(0,285,36,35,3,ILI9341_WHITE);
tft.fillTriangle(5,310,31,310,18,295,ILI9341_BLACK);
tft.fillRoundRect(44,285,36,35,3,ILI9341_WHITE);
tft.fillTriangle(49,295,75,295,62,310,ILI9341_BLACK);
tft.fillRoundRect(88,285,45,35,3,ILI9341_WHITE);
tft.setTextSize(1);
tft.setTextColor(ILI9341_BLACK);
tft.setCursor(100,300);
tft.print("Time");
tft.fillRoundRect(141,285,45,35,3,ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK);
tft.setCursor(150,300);
tft.print("Alarm");
tft.fillRoundRect(194,285,45,35,3,ILI9341_WHITE);
tft.setTextColor(ILI9341_BLACK);
tft.setCursor(210,300);
tft.print("GMT");
PreviousMillis = millis();
}
void loop() {
String GMTT = "GMT+"+String(GMT); //untuk menampilkan status GMT
if ( (millis() - PreviousMillis) > 1000) {
PreviousMillis = millis();
tmElements_t tm;
if(RTC.read(tm)){
if(running == true){//pembacaan RTC
hh=tm.Hour+rh; //data hh hasil dari Jam RTC+revisi hour dalam time
mm=tm.Minute+rm; //data mm hasil dari menit RTC+revisi minute dalam time
rtcs=tm.Second; //data rtcs hasil dari detik RTC
}
dateStr = String(tm.Day) + "-" + String(tm.Month) + "-" + String(tmYearToCalendar(tm.Year));
tft.drawRoundRect(85,170,68,16,3,ILI9341_CYAN);
drawCenterString(dateStr, 1, 174, ILI9341_WHITE);
}
// Pre-compute hand degrees, x & y coords for a fast screen update
sdeg = ss*6; // 0-59 -> 0-354
mdeg = mm*6+sdeg*0.01666667; // 0-59 -> 0-360 - includes seconds
hdeg = hh*30+mdeg*0.0833333; // 0-11 -> 0-360 - includes minutes and seconds
hx = cos((hdeg-90)*0.0174532925);
hy = sin((hdeg-90)*0.0174532925);
mx = cos((mdeg-90)*0.0174532925);
my = sin((mdeg-90)*0.0174532925);
sx = cos((sdeg-90)*0.0174532925);
sy = sin((sdeg-90)*0.0174532925);
if (ss==0 || initial) {
initial = 0;
// Erase hour and minute hand positions every minute
tft.drawLine(ohx-1, ohy+center, 119, 120+center, ILI9341_BLACK);
tft.drawLine(ohx, ohy+center, 120, 120+center, ILI9341_BLACK);
tft.drawLine(ohx+1, ohy+center, 121, 120+center, ILI9341_BLACK);
ohx = hx*62+120;
ohy = hy*62+120;
tft.drawLine(omx-1, omy+center, 119, 120+center, ILI9341_BLACK);
tft.drawLine(omx, omy+center, 120, 120+center, ILI9341_BLACK);
tft.drawLine(omx+1, omy+center, 121, 120+center, ILI9341_BLACK);
omx = mx*84+120;
omy = my*84+120;
drawCenterString((GMTT), 2, 265, ILI9341_GREY);
}
// Redraw new hand positions, hour and minute hands not erased here to avoid flicker
tft.drawLine(osx, osy+center, 120, 120+center, ILI9341_BLACK);
osx = sx*90+121;
osy = sy*90+121;
tft.drawLine(osx, osy+center, 120, 120+center, ILI9341_RED);
// draw Round Rectangle and Print Date
tft.drawRoundRect(85,170,68,16,3,ILI9341_CYAN);
drawCenterString(dateStr, 1, 174, ILI9341_WHITE);
tft.drawLine(ohx-1, ohy+center, 119, 120+center, ILI9341_GREEN);
tft.drawLine(ohx, ohy+center, 120, 120+center, ILI9341_GREEN);
tft.drawLine(ohx+1, ohy+center, 121, 120+center, ILI9341_GREEN);
tft.drawLine(omx-1, omy+center, 119, 120+center, ILI9341_GREEN);
tft.drawLine(omx, omy+center, 120, 120+center, ILI9341_GREEN);
tft.drawLine(omx+1, omy+center, 121, 120+center, ILI9341_GREEN);
tft.drawLine(osx, osy+center, 120, 120+center, ILI9341_RED);
tft.fillCircle(120, 120+center, 4, ILI9341_RED);
drawCenterString((GMTT), 2, 265, ILI9341_YELLOW);
if(int(hh)==int(rha) && int(mm)==int(rma)){ //untuk cek alarm == jam
relay=true;
}
if(pagetime==0){ //default jam analog
ss=rtcs;
}
if(pagetime==1 || pageGMT ==1){
//ketika pada mode time/GMT, tampilan hh akan ditambahkan dari hasil revisi hour dan jam rtc
hh=hh+rh;
mm=mm+rm;
ss=0;
Serial.println("Jam"+String(hh)+":"+String(mm));
}
if(pagetime==2){
//ketika pada mode time/GMT, tampilan mm akan ditambahkan dari hasil revisi hour dan menit rtc
hh=hh+rh;
mm=mm+rm;
ss=0;
Serial.println("Jam"+String(hh)+":"+String(mm));
}
if(pagealarm==0 || pageGMT==0){
running = true; //membuat RTC running kembali
if(!hold){//untuk menahan relay supaya tetap posisi OFF
relay=false;
hold=true;
}
if(!ss0){//untuk mereset detik agar kembali ke jam utama, dan hanya dijalankan 1x saja
ss=0;
ss0 = true;
}
}
if(pagealarm==1){
//ketika pada mode alarm, tampilan hh merupakan tampilan jam alarm
running = false; //untuk memberhentikan RTC agar tidak tidak terganggu
relay=false;
hh=rha;
mm=rma;
ss=0; //untuk membuat detik pada posisi 0
Serial.println("Alarm"+String(rha)+":"+String(rma));
}
if(pagealarm==2){
//ketika pada mode alarm, tampilan mm merupakan tampilan menit alarm
running = false;
relay=false;
hh=rha;
mm=rma;
ss=0;
Serial.println("Alarm "+String(rha)+":"+String(rma));
}
}
if(relay==true){
//ketika alarm==jam, maka relay akan ON
pinMode(8,OUTPUT);
digitalWrite(8, HIGH);
}
if(relay==false){
//ketika relay ON dan tombol alarm ditekan maka relay akan OFF
pinMode(8,OUTPUT);
digitalWrite(8, LOW);
}
// Wait for a touch
if (! ctp.touched()) {
drawCenterString("", 2, 265, ILI9341_GREY);
return;
}
// Retrieve a point
TS_Point p = ctp.getPoint();
// flip it around to match the screen.
p.x = map(p.x, 0, 240, 240, 0);
p.y = map(p.y, 0, 320, 320, 0);
if (isTouchInArea(p.x, p.y, BUTTON_UP_X, BUTTON_UP_Y, BUTTON_UP_W, BUTTON_UP_H)) {
if(pagetime==1 || pageGMT==1){ //ketika pada menu time=1 / GMT akan menambah jam
rh+=1;
GMT+=1;
Serial.println("Jam"+String(hh)+":"+String(mm));
tft.fillRoundRect(0,263,200,20,3,ILI9341_GREY);
if(hh==24){ //membatasi jam apabila sudah lewat dari 24 maka akan kembali ke 0
hh=0;
}
if(GMT==16){ //membatasi GMT apabila sudah lewat dari 15 maka akan kembali ke -12
GMT=-12;
}
}
else if(pagetime==2){ //ketika pada menu time=2, akan menambah menit
rm+=1;
if(mm==60){ //membatasi menit apabila sudah lewat dari 59 maka akan kembali ke 0
mm=0;
}
}
else if(pagealarm==1){ //ketika pada menu alarm=1, akan menambah jam alarm
rha+=1;
if(rha==24){
rha=0;
}
}
else if(pagealarm==2){ //ketika pada menu alarm=2, akan menambah menit alarm
rma+=1;
if(rma==60){
rma=0;
}
}
delay(200); //delay supaya respon touch tidak banyak dalam 1x tekan
}
else if (isTouchInArea(p.x, p.y, BUTTON_DOWN_X, BUTTON_DOWN_Y, BUTTON_DOWN_W, BUTTON_DOWN_H)) {
if(pagetime==1 || pageGMT == 1){
//ketika pada menu time=1 / GMT akan mengurangi jam
rh-=1;
GMT-=1;
tft.fillRoundRect(0,263,200,20,3,ILI9341_GREY);
if(hh==-1){
hh=23;
}
if(GMT==-13){
GMT=15;
}
}
else if(pagetime==2){
//ketika pada menu time=2 akan mengurangi menit
rm-=1;
if(mm==-1){
mm=59;
}
}
else if(pagealarm==1){
//ketika pada menu alarm=1 akan mengurangi jam alarm
rha-=1;
if(rha==-1){
rha=23;
}
}
else if(pagealarm==2){
//ketika pada menu alarm=2 akan mengurangi menit alarm
rma-=1;
if(rma==-1){
rma=59;
}
}
delay(200);
}
if (isTouchInArea(p.x, p.y, BUTTON_TIME_X, BUTTON_TIME_Y, BUTTON_TIME_W, BUTTON_TIME_H)) {
pagetime +=1;
if(pagetime == 3){ //menambah pagetime, ketika sudah >2 maka akan kembali ke 0
pagetime -=3;
}
Serial.println("Time button pressed");
delay(200);
}
if (isTouchInArea(p.x, p.y, BUTTON_ALARM_X, BUTTON_ALARM_Y, BUTTON_ALARM_W, BUTTON_ALARM_H)) {
if(relay==false){//ketika relay off, maka tombol alarm untuk set alarm
pagealarm +=1;
hold=false;
ss0= false;
if(pagealarm == 3){ //menambah pagealarm, ketika sudah >2 maka akan kembali ke 0
pagealarm -=3;
}
}
if(relay==true){//ketika relay on, maka tombol alarm untuk mematikan relay
relay=false;
}
Serial.println("Alarm button pressed");
delay(200);
}
if (isTouchInArea(p.x, p.y, BUTTON_GMT_X, BUTTON_GMT_Y, BUTTON_GMT_W, BUTTON_GMT_H)) {
Serial.println("GMT button pressed");
ss0=false;
pageGMT+=1;
if(pageGMT==2){
pageGMT=0;
}
delay(200);
}
}
// Fungsi untuk menggambar teks di tengah
void drawCenterString(const String& text, int textSize, int y, uint16_t color) {
tft.setTextSize(textSize);
tft.setTextColor(color);
// Hitung lebar teks
int16_t x1, y1;
uint16_t w, h;
tft.getTextBounds(text, 0, y, &x1, &y1, &w, &h);
// Hitung posisi X untuk menempatkan teks di tengah layar
int x = (tft.width() - w) / 2;
// Cetak teks di posisi yang sudah ditentukan
tft.setCursor(x, y);
tft.print(text);
}
// print hour text 3,6,9 and 12
void printHourText() {
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(2);
tft.setCursor(205,113+center);
tft.print("3");
drawCenterString("6", 2, 200+center, ILI9341_WHITE);
tft.setCursor(25,113+center);
tft.print("9");
drawCenterString("12", 2, 25+center, ILI9341_WHITE);
}