Arduino TFT LCD Dokunmatik Hesap Makinesi Yapımı

👤 Yazar: ozcan 📅 Tarih: 15.07.2026 12:19 👁️ Görüntüleme: 17

Arduino TFT LCD Dokunmatik Hesap Makinesi Yapımı

Bu projemizde, Arduino Uno ve Shield tipi dokunmatik TFT LCD ekran kullanarak tamamen işlevsel, dört işlem yapabilen görsel bir hesap makinesi tasarlıyoruz. Proje, sadece buton çizip dokunmayı algılamanın ötesine geçerek; girilen sayıları hafızada tutma, işlem operatörlerini yönetme ve float (ondalıklı sayı) hesaplamaları yapabilme gibi gelişmiş mantıksal süreçleri içerir.

Arduino TFT LCD Dokunmatik Hesap Makinesi Projesi

Görsel: TFT LCD Ekran Üzerinde Çalışan Dört İşlem Hesap Makinesi Arayüzü

Projede Kullanılan Kütüphaneler ve Görevleri

Projenin donanımsal bileşenlerini kontrol etmek için iki temel kütüphaneye ihtiyaç duyarız:

  • TFTLCD.h (veya Adafruit_GFX / MCUFRIEND_kbv): Ekran üzerine buton çerçevelerini çizmek, renk paletini belirlemek ve sayıları/sonuçları ekrana yazdırmak için kullanılır.
  • TouchScreen.h: Ekranın üzerindeki rezistif dokunmatik katmandan gelen analog verileri (X, Y koordinatları ve dokunma basıncı Z) okumamızı sağlar.

Arayüz Tasarımı ve Koordinat Planlama

Ekran yerleşimini kusursuz yapabilmek için dikey (Portrait) modda çalışıyoruz. Ekranı kabaca iki ana bölgeye ayırıyoruz:

  1. Gösterge Paneli (Display Area): Ekranın en üst kısmında (0 ila 70. piksel arası dikey alan) yer alan, arka planı genellikle siyah veya mavi olan bölümdür. Burada kullanıcının o an yazdığı sayılar veya hesaplama sonucu gösterilir.
  2. Buton Matrisi (Keypad Area): Ekranın geri kalan alt kısmında 4 satır ve 4 sütun (toplam 16 buton) şeklinde organize edilen bölümdür. Sayılar (0-9), operatörler (+, -, *, /), temizleme (C) ve eşittir (=) butonları dikey ve yatay boşluklar (GAP) hesaplanarak ekrana matematiksel bir döngüyle çizilir.

Yazılımsal İşlem Algoritması Nasıl Çalışıyor?

Hesap makinesinin arkasındaki matematiksel mantık, durum makineleri (state machines) mantığına dayanır:

  • Sayı Girişi: Kullanıcı rakam butonlarına dokundukça, bu rakamlar string (metin) tipinde uç uca eklenir (Örn: "1" + "2" = "12"). Bu metin anlık olarak ekrandaki gösterge paneline yazdırılır.
  • Operatör Seçimi: Bir işlem butonuna (+, -, *, /) basıldığında, ekrandaki mevcut sayı float tipine dönüştürülerek birinciSayi değişkenine kaydedilir. Seçilen işlem türü bir değişkende (örn. char islem = '+') tutulur ve ekran yeni sayı girişi için temizlenir.
  • Sonuç Hesaplama: Eşittir (=) butonuna dokunulduğunda, ekrandaki güncel değer ikinciSayi olarak alınır. switch-case kontrol yapısı kullanılarak seçilen operatöre göre matematiksel işlem yapılır ve çıkan sonuç tekrar string'e dönüştürülerek gösterge ekranına basılır.

Önemli İpucu: Dokunmatik Ekran Kalibrasyonu

Her TFT ekranın dokunmatik hassasiyeti ve koordinat sınırları birebir aynı değildir. Eğer dokunduğunuz buton yerine yanındaki buton tetikleniyorsa, kodun başındaki TS_MINX, TS_MAXX, TS_MINY ve TS_MAXY sınır değerlerini kendi ekranınıza göre kalibre etmeniz gerekir. Bunun için Arduino'nun analog pinlerinden gelen ham X ve Y değerlerini seri porttan okuyup kodunuzda güncellemelisiniz.

Arduino Proje Kodları

#include "TFTLCD.h"
#include "TouchScreen.h"
#include <EEPROM.h>

// Dokunmatik Ekran Donanımsal Pinleri
#define YP A1
#define XM A2
#define YM 7
#define XP 6

TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);

// TFT LCD Kontrol Pinleri
#define LCD_CS A3
#define LCD_CD A2
#define LCD_WR A1
#define LCD_RD A0
#define LCD_RESET A4

// 16-bit Gelişmiş Renk Paleti
#define BLACK     0x0000
#define BLUE      0x001F
#define RED       0xF800
#define GREEN     0x07E0
#define WHITE     0xFFFF
#define GRAY      0x7BEF
#define DARK_GRAY 0x31A6
#define CYAN      0x07FF

TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);

// 5-Nokta Kalibrasyon Katsayıları (Varsayılan dikey ekran değerleri)
float tsA = 0.3117;
float tsB = 0.0;
float tsC = -46.75;
float tsD = 0.0;
float tsE = -0.39;
float tsF = 366.8;

// EEPROM'da saklanacak kalibrasyon verisi yapısı
struct CalibData {
  byte magic; // Kalibrasyon geçerlilik imzası (0xCD)
  float A;
  float B;
  float C;
  float D;
  float E;
  float F;
};

// 4x4 Hesap Makinesi Tuş Takımı Matrisi
char keys[4][4] = {
  {'1', '2', '3', '+'},
  {'4', '5', '6', '-'},
  {'7', '8', '9', '*'},
  {'C', '0', '=', '/'}
};

// Ekran ve Buton Düzeni Parametreleri
#define START_X 14   // İlk sütunun sol kenar uzaklığı
#define START_Y 125  // İlk satırın üst kenar uzaklığı
#define BTN_W   48   // Buton genişliği
#define BTN_H   40   // Buton yüksekliği
#define GAP_X   10   // Butonlar arası yatay boşluk
#define GAP_Y   8    // Butonlar arası dikey boşluk

#define MINPRESSURE 10
#define MAXPRESSURE 1000

// Hesap Makinesi Çalışma Değişkenleri
String currentNum = "";      
double operand1 = 0;         
char op = '\0';              
String historyStr = "";      
bool showResult = false;     
double resultValue = 0;      

void setup(void) {
  Serial.begin(9600);

  tft.reset();
  tft.initDisplay();
  tft.setRotation(0); // Dikey Ekran Yönü (240x320)

  // İlk açılışta kalibrasyon yönetim ekranını başlat
  kalibrasyonYonetimi();

  // Hesap makinesi ana arayüzünü çiz
  hesapMakinesiArayuzuCiz();
}

void kalibrasyonYonetimi() {
  tft.fillScreen(BLACK);
  
  // Başlık Şeridi
  tft.fillRect(0, 2, tft.width(), 38, BLUE);
  tft.drawString(35, 14, "EKRAN AYARLARI", WHITE, 2);

  tft.drawString(15, 60, "Ekraninizi kalibre", WHITE, 2);
  tft.drawString(15, 85, "etmek ister misiniz?", WHITE, 2);

  // Butonları Çiz
  // KALIBRE ET Butonu (Yeşil)
  tft.fillRect(15, 140, 210, 45, GREEN);
  tft.drawRect(15, 140, 210, 45, WHITE);
  tft.drawString(55, 154, "KALIBRE ET", BLACK, 2);

  // GEC/BASLA Butonu (Kırmızı)
  tft.fillRect(15, 205, 210, 45, RED);
  tft.drawRect(15, 205, 210, 45, WHITE);
  tft.drawString(45, 219, "GEC / BASLA", WHITE, 2);

  tft.drawString(15, 275, "Otomatik gecis süresi:", GRAY, 1);

  unsigned long startTime = millis();
  int remainingSeconds = 5;
  bool secimYapildi = false;

  while (millis() - startTime < 5000) {
    int elapsed = (millis() - startTime) / 1000;
    int currentRemaining = 5 - elapsed;
    
    if (currentRemaining != remainingSeconds) {
      remainingSeconds = currentRemaining;
      tft.fillRect(160, 272, 40, 20, BLACK);
      tft.drawString(160, 272, (String(remainingSeconds) + " sn").c_str(), RED, 1);
    }

    TSPoint p = ts.getPoint();
    pinMode(XM, OUTPUT);
    pinMode(YP, OUTPUT);
    digitalWrite(XM, HIGH);
    digitalWrite(YP, HIGH);

    if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {
      // Geçici katsayılarla kaba koordinat kontrolü yapıyoruz
      int tx = tsA * p.x + tsB * p.y + tsC;
      int ty = tsD * p.x + tsE * p.y + tsF;
      tx = constrain(tx, 0, tft.width() - 1);
      ty = constrain(ty, 0, tft.height() - 1);

      // "KALIBRE ET" buton alanı kontrolü
      if (tx > 15 && tx < 225 && ty > 140 && ty < 185) {
        dokunmaBirakilanaKadarBekle();
        kalibrasyonYap5Nokta();
        secimYapildi = true;
        break;
      }
      // "GEC / BASLA" buton alanı kontrolü
      if (tx > 15 && tx < 225 && ty > 205 && ty < 250) {
        dokunmaBirakilanaKadarBekle();
        eepromYukle();
        secimYapildi = true;
        break;
      }
    }
    delay(50);
  }

  // Kullanıcı dokunmazsa EEPROM verilerini otomatik yükler
  if (!secimYapildi) {
    eepromYukle();
  }
}

void kalibrasyonYap5Nokta() {
  tft.fillScreen(BLACK);
  tft.drawString(30, 100, "5-NOKTALI HASSAS", CYAN, 2);
  tft.drawString(30, 130, "KALIBRASYON", CYAN, 2);
  tft.drawString(30, 160, "BASLIYOR...", WHITE, 2);
  delay(1500);

  // 5 Referans Noktasının LCD Üzerindeki Hedef Piksel Koordinatları
  long tX[5] = {30,  210, 30,  210, 120}; // X Hedefleri
  long tY[5] = {40,  40,  280, 280, 160}; // Y Hedefleri
  
  // Dokunmatik panelden okunacak raw koordinatlar
  long rX[5] = {0, 0, 0, 0, 0};
  long rY[5] = {0, 0, 0, 0, 0};

  const char* adimIsimleri[5] = {
    "1/5: SOL-UST HEDEF",
    "2/5: SAG-UST HEDEF",
    "3/5: SOL-ALT HEDEF",
    "4/5: SAG-ALT HEDEF",
    "5/5: ORTA HEDEF"
  };

  for (int i = 0; i < 5; i++) {
    hedefCiz(tX[i], tY[i], adimIsimleri[i]);
    
    // Gürültüyü engellemek için kararlı çoklu dokunma okuması yapıyoruz
    long rawXSum = 0;
    long rawYSum = 0;
    int basariliOkuma = 0;
    
    // İlk dokunuşu bekle
    while (true) {
      TSPoint p = ts.getPoint();
      pinMode(XM, OUTPUT);
      pinMode(YP, OUTPUT);
      digitalWrite(XM, HIGH);
      digitalWrite(YP, HIGH);
      if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {
        delay(100); // Sinyal kararlılığı için bekleme
        break;
      }
    }

    // 16 adet ardışık ham örnek alıp ortalamasını çıkartıyoruz
    for (int numSamples = 0; numSamples < 16; numSamples++) {
      TSPoint p = ts.getPoint();
      pinMode(XM, OUTPUT);
      pinMode(YP, OUTPUT);
      digitalWrite(XM, HIGH);
      digitalWrite(YP, HIGH);
      if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {
        rawXSum += p.x;
        rawYSum += p.y;
        basariliOkuma++;
      }
      delay(15);
    }

    rX[i] = rawXSum / basariliOkuma;
    rY[i] = rawYSum / basariliOkuma;

    // Bir sonraki noktaya geçmeden önce dokunmanın tamamen bittiğinden emin oluyoruz
    dokunmaBirakilanaKadarBekle();
  }

  // --- MATEMATİKSEL MATRİS HESAPLAMA (En Küçük Kareler Çözümü) ---
  float nA, nB, nC, nD, nE, nF;
  if (calculateLeastSquares(rX, rY, tX, tY, nA, nB, nC, nD, nE, nF)) {
    // Başarılı ise doğrulama ekranına yönlendir
    dogrulamaVeTestEkrani(nA, nB, nC, nD, nE, nF);
  } else {
    // Hatalı hesaplama durumunda yeniden başlat
    tft.fillScreen(BLACK);
    tft.drawString(20, 120, "HATA: KALIBRASYON", RED, 2);
    tft.drawString(20, 150, "BASARISIZ OLDU!", RED, 2);
    delay(2000);
    kalibrasyonYap5Nokta();
  }
}

bool calculateLeastSquares(long rx[], long ry[], long tx[], long ty[], float &outA, float &outB, float &outC, float &outD, float &outE, float &outF) {
  double Sxx = 0, Sxy = 0, Sx = 0, Syy = 0, Sy = 0;
  double Vx0 = 0, Vx1 = 0, Vx2 = 0;
  double Vy0 = 0, Vy1 = 0, Vy2 = 0;

  for (int i = 0; i < 5; i++) {
    double x = rx[i];
    double y = ry[i];
    double X = tx[i];
    double Y = ty[i];

    Sxx += x * x;
    Sxy += x * y;
    Sx  += x;
    Syy += y * y;
    Sy  += y;

    Vx0 += x * X;
    Vx1 += y * X;
    Vx2 += X;

    Vy0 += x * Y;
    Vy1 += y * Y;
    Vy2 += Y;
  }

  // Symmetric Matrix (M^T * M)
  // [ Sxx  Sxy  Sx ]
  // [ Sxy  Syy  Sy ]
  // [ Sx   Sy   5  ]
  double a = Sxx;
  double b = Sxy;
  double c = Sx;
  double e = Syy;
  double f = Sy;
  double k = 5.0; // 5 Nokta kullandığımız için N = 5

  // Determinant hesabı
  double det = a * (e * k - f * f) - b * (b * k - c * f) + c * (b * f - c * e);

  if (abs(det) < 0.0001) {
    return false; // Sıfıra bölünme hatası / Çakışık koordinatlar
  }

  // Adjugate matris elemanlarının hesabı
  double m00 = e * k - f * f;
  double m01 = c * f - b * k;
  double m02 = b * f - c * e;
  double m11 = a * k - c * c;
  double m12 = b * c - a * f;
  double m22 = a * e - b * b;

  // X ekseni katsayılarının (A, B, C) hesabı
  outA = (m00 * Vx0 + m01 * Vx1 + m02 * Vx2) / det;
  outB = (m01 * Vx0 + m11 * Vx1 + m12 * Vx2) / det;
  outC = (m02 * Vx0 + m12 * Vx1 + m22 * Vx2) / det;

  // Y ekseni katsayılarının (D, E, F) hesabı
  outD = (m00 * Vy0 + m01 * Vy1 + m02 * Vy2) / det;
  outE = (m01 * Vy0 + m11 * Vy1 + m12 * Vy2) / det;
  outF = (m02 * Vy0 + m12 * Vy1 + m22 * Vy2) / det;

  return true;
}

void hedefCiz(int x, int y, const char* baslik) {
  tft.fillScreen(BLACK);
  tft.drawString(10, 10, baslik, CYAN, 2);
  
  // Milimetrik hedef çizimi
  tft.drawLine(x - 20, y, x + 20, y, RED);
  tft.drawLine(x, y - 20, x, y + 20, RED);
  tft.drawCircle(x, y, 6, WHITE);
  tft.drawCircle(x, y, 12, BLUE);
  tft.drawCircle(x, y, 18, WHITE);
  
  tft.drawString(15, 140, "Kalem ucuyla tam", WHITE, 2);
  tft.drawString(15, 170, "merkeze dokunup", WHITE, 2);
  tft.drawString(15, 200, "bekleyin.", WHITE, 2);
}

void dogrulamaVeTestEkrani(float nA, float nB, float nC, float nD, float nE, float nF) {
  tft.fillScreen(BLACK);
  
  // Çizim Alanı Sınırı
  tft.drawRect(5, 5, 230, 220, GRAY);
  tft.drawString(10, 15, "TEST ALANI: Ekrana", CYAN, 1);
  tft.drawString(10, 30, "dokunarak cizgi cizin.", CYAN, 1);
  tft.drawString(10, 45, "Sapma yoksa KAYDET,", CYAN, 1);
  tft.drawString(10, 60, "varsa YENIDEN basin.", CYAN, 1);

  // KAYDET Butonu (Yeşil)
  tft.fillRect(10, 240, 105, 50, GREEN);
  tft.drawRect(10, 240, 105, 50, WHITE);
  tft.drawString(25, 258, "KAYDET", BLACK, 2);

  // YENIDEN Butonu (Kırmızı)
  tft.fillRect(125, 240, 105, 50, RED);
  tft.drawRect(125, 240, 105, 50, WHITE);
  tft.drawString(135, 258, "YENIDEN", WHITE, 2);

  bool kararVerildi = false;

  while (!kararVerildi) {
    TSPoint p = ts.getPoint();
    pinMode(XM, OUTPUT);
    pinMode(YP, OUTPUT);
    digitalWrite(XM, HIGH);
    digitalWrite(YP, HIGH);

    if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {
      // Yeni 5-noktalı katsayılar ile milimetrik test koordinatı hesabı
      int testX = nA * p.x + nB * p.y + nC;
      int testY = nD * p.x + nE * p.y + nF;

      testX = constrain(testX, 0, tft.width() - 1);
      testY = constrain(testY, 0, tft.height() - 1);

      // Test çizim alanı içi
      if (testX > 8 && testX < 228 && testY > 8 && testY < 220) {
        tft.fillCircle(testX, testY, 2, GREEN);
      }

      // "KAYDET" butonu
      if (testX > 10 && testX < 115 && testY > 240 && testY < 290) {
        dokunmaBirakilanaKadarBekle();
        
        // Yeni katsayıları ana çalışma değişkenlerine aktar
        tsA = nA; tsB = nB; tsC = nC;
        tsD = nD; tsE = nE; tsF = nF;

        // EEPROM'a kalıcı olarak kaydet
        CalibData data;
        data.magic = 0xCD;
        data.A = tsA; data.B = tsB; data.C = tsC;
        data.D = tsD; data.E = tsE; data.F = tsF;
        EEPROM.put(0, data);

        tft.fillScreen(BLACK);
        tft.drawString(30, 120, "KALIBRASYON", GREEN, 2);
        tft.drawString(30, 150, "KAYDEDILDI!", GREEN, 2);
        delay(1500);
        kararVerildi = true;
      }

      // "YENIDEN" butonu
      if (testX > 125 && testX < 230 && testY > 240 && testY < 290) {
        dokunmaBirakilanaKadarBekle();
        kalibrasyonYap5Nokta(); // Kalibrasyon döngüsünü baştan başlatır
        kararVerildi = true;
      }
    }
  }
}

void eepromYukle() {
  CalibData data;
  EEPROM.get(0, data);

  if (data.magic == 0xCD) {
    tsA = data.A;
    tsB = data.B;
    tsC = data.C;
    tsD = data.D;
    tsE = data.E;
    tsF = data.F;
    Serial.println("Kayitli kalibrasyon verileri yuklendi.");
  } else {
    // Hafıza boş ise standart dikey ekran katsayılarını koru
    tsA = 0.3117; tsB = 0.0; tsC = -46.75;
    tsD = 0.0; tsE = -0.39; tsF = 366.8;
    Serial.println("Gecerli kalibrasyon yok! Varsayilan yuklendi.");
  }
}

void dokunmaBirakilanaKadarBekle() {
  delay(100);
  bool basili = true;
  while (basili) {
    TSPoint p = ts.getPoint();
    pinMode(XM, OUTPUT);
    pinMode(YP, OUTPUT);
    digitalWrite(XM, HIGH);
    digitalWrite(YP, HIGH);
    if (p.z < MINPRESSURE || p.z > MAXPRESSURE) {
      basili = false;
    }
    delay(30);
  }
  delay(100);
}

uint16_t butonRengiAl(char tus) {
  if (tus == 'C') {
    return RED;       
  } else if (tus == '=') {
    return GREEN;     
  } else if (tus == '+' || tus == '-' || tus == '*' || tus == '/') {
    return BLUE;      
  } else {
    return DARK_GRAY; 
  }
}

void tusIslemiYap(char tus) {
  Serial.print("Basilan Tus: ");
  Serial.println(tus);

  if (tus >= '0' && tus <= '9') {
    if (showResult) {
      temizle();
    }
    if (currentNum == "0") {
      currentNum = String(tus);
    } else {
      currentNum += tus;
    }
  } 
  else if (tus == 'C') {
    temizle();
  } 
  else if (tus == '+' || tus == '-' || tus == '*' || tus == '/') {
    if (showResult) {
      operand1 = resultValue;
      op = tus;
      historyStr = formatSayi(operand1) + " " + String(op);
      currentNum = "";
      showResult = false;
    } 
    else if (currentNum != "") {
      operand1 = currentNum.toFloat();
      op = tus;
      historyStr = currentNum + " " + String(op);
      currentNum = "";
    } 
    else if (op != '\0') {
      op = tus;
      historyStr = formatSayi(operand1) + " " + String(op);
    }
  } 
  else if (tus == '=') {
    if (op != '\0' && currentNum != "") {
      double operand2 = currentNum.toFloat();
      
      switch (op) {
        case '+': resultValue = operand1 + operand2; break;
        case '-': resultValue = operand1 - operand2; break;
        case '*': resultValue = operand1 * operand2; break;
        case '/': 
          if (operand2 != 0) {
            resultValue = operand1 / operand2;
          } else {
            resultValue = NAN; 
          }
          break;
      }
      
      historyStr = formatSayi(operand1) + " " + String(op) + " " + currentNum + " =";
      showResult = true;
      currentNum = "";
      op = '\0';
    }
  }

  ekraniGuncelle();
}

String formatSayi(double deger) {
  if (isnan(deger)) return "Hata";
  if (isinf(deger)) return "Limit Disi";
  
  if (deger == (long)deger) {
    return String((long)deger);
  } else {
    return String(deger, 2);
  }
}

void temizle() {
  currentNum = "";
  operand1 = 0;
  op = '\0';
  historyStr = "";
  showResult = false;
  resultValue = 0;
}

void ekraniGuncelle() {
  tft.fillRect(6, 46, 228, 68, BLACK);
  
  // Üst Satır: İşlem Geçmişi
  tft.drawString(15, 54, historyStr.c_str(), GRAY, 2);
  
  // Alt Satır: Sonuç veya güncel girdi
  if (showResult) {
    tft.drawString(15, 84, formatSayi(resultValue).c_str(), GREEN, 3);
  } 
  else if (currentNum == "" && op != '\0') {
    tft.drawString(15, 84, formatSayi(operand1).c_str(), WHITE, 3);
  } 
  else if (currentNum != "") {
    tft.drawString(15, 84, currentNum.c_str(), WHITE, 3);
  } 
  else {
    tft.drawString(15, 84, "0", WHITE, 3);
  }
}

void hesapMakinesiArayuzuCiz() {
  tft.fillScreen(BLACK);
  
  // Üst Mavi Şerit
  tft.fillRect(0, 2, tft.width(), 38, BLUE);
  tft.drawString(45, 14, "HESAP MAKINESI", WHITE, 2); 

  // Çerçeve
  tft.drawRect(5, 45, 230, 70, BLUE);

  ekraniGuncelle();

  // Butonları Çiziyoruz (4x4)
  for (int satir = 0; satir < 4; satir++) {
    for (int sutun = 0; sutun < 4; sutun++) {
      
      int btnX = START_X + (sutun * (BTN_W + GAP_X));
      int btnY = START_Y + (satir * (BTN_H + GAP_Y));
      char tusValue = keys[satir][sutun];
      
      uint16_t btnColor = butonRengiAl(tusValue);
      
      tft.fillRect(btnX, btnY, BTN_W, BTN_H, btnColor);
      tft.drawRect(btnX, btnY, BTN_W, BTN_H, WHITE);
      
      uint16_t textColor = (tusValue == '=') ? BLACK : WHITE;
      tft.drawString(btnX + 18, btnY + 12, String(tusValue).c_str(), textColor, 2);
    }
  }
}

void loop() {
  TSPoint p = ts.getPoint();

  pinMode(XM, OUTPUT);
  pinMode(YP, OUTPUT);
  digitalWrite(XM, HIGH);
  digitalWrite(YP, HIGH);

  if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {
    // 5-Noktalı LSM matrisinden hesaplanan hassas koordinatlar
    int x = tsA * p.x + tsB * p.y + tsC;
    int y = tsD * p.x + tsE * p.y + tsF;

    x = constrain(x, 0, tft.width() - 1);
    y = constrain(y, 0, tft.height() - 1);

    // Buton Dokunma Kontrolü
    for (int satir = 0; satir < 4; satir++) {
      for (int sutun = 0; sutun < 4; sutun++) {
        
        int btnX = START_X + (sutun * (BTN_W + GAP_X));
        int btnY = START_Y + (satir * (BTN_H + GAP_Y));

        if (x > btnX && x < (btnX + BTN_W) && y > btnY && y < (btnY + BTN_H)) {
          char tusValue = keys[satir][sutun];
          
          // Görsel Geri Bildirim (Buton Basıldı Efekti)
          tft.fillRect(btnX, btnY, BTN_W, BTN_H, WHITE);
          tft.drawString(btnX + 18, btnY + 12, String(tusValue).c_str(), BLACK, 2);
          
          tusIslemiYap(tusValue);
          
          delay(250); // Debounce engelleme

          // Eski rengine geri döndürme
          uint16_t btnColor = butonRengiAl(tusValue);
          tft.fillRect(btnX, btnY, BTN_W, BTN_H, btnColor);
          tft.drawRect(btnX, btnY, BTN_W, BTN_H, WHITE);
          
          uint16_t textColor = (tusValue == '=') ? BLACK : WHITE;
          tft.drawString(btnX + 18, btnY + 12, String(tusValue).c_str(), textColor, 2);
        }
      }
    }
  }
}

Geliştirme Önerileri

Eğer projeyi daha da ileriye taşımak isterseniz; kod yapısına ondalıklı sayılar için nokta (.) butonu ekleyebilir, sıfıra bölme hatasını (Error) engelleyen güvenlik sorguları yazabilir veya Arduino'nun EEPROM hafızasını kullanarak geçmiş işlemler için bir "Memory (M+, M-)" fonksiyonu entegre edebilirsiniz.

💬 Yorumlar

Henüz yorum yapılmamış. İlk yorumu siz yapın!

Bir Yorum Bırakın

Güvenlik Kontrolü:

Yenidir.com
↑ Sayfa Başı
📞 İletişim ✉ E-Posta Gönder 🟥 YouTube
© 2026 Yenidir.com
Yenidir CMS V0.1