Bu rehberde, amatör projelerden sıyrılıp endüstriyel cihaz kalitesine göz kırpan gelişmiş bir Arduino projesini inceliyoruz: TFT LCD Dokunmatik Ekranlı Akıllı Kilit Sistemi. Bu sistemi özel kılan şey, hem milimetrik dokunma doğruluğu sağlayan 5 Noktalı Kalibrasyon Algoritması'nı barındırması hem de şifre ve motor kontrolünü tek bir kararlı Durum Makinesi (State Machine) mimarisi ile yönetmesidir.

Görsel: Arduino platformu üzerinde kilit ve ekran sürücü devrelerinin test edilmesi
Projenin arkasındaki yazılım tasarımı, karmaşık işlemleri bile Arduino'yu yormadan tıkır tıkır çalıştıracak şekilde optimize edilmiştir. Kodun en dikkat çekici mühendislik detayları şunlardır:
KILITLI, ACILDI, ADMIN_MENUSU ve KALIB olmak üzere 4 ana durum üzerinden döner. Bu sayede buton basma algoritmaları birbirine karışmaz ve gereksiz kaynak tüketimi önlenir.0. adresten itibaren kalibrasyon katsayıları (float formatında), 30. adresten itibaren ise 4 haneli kilit şifresi güvenli imza (Magic Byte) kontrolleriyle saklanır.Projenin donanımsal altyapısı standart bir Uno ve TFT Shield üzerine kuruludur:
| Bileşen / Pin | Arduino Pin Bağlantısı | Görevi |
|---|---|---|
| Dokunmatik Pinleri (YP, XM, YM, XP) | A1, A2, D7, D6 | Ekranın dokunmatik analog koordinatlarını okur. |
| TFT Kontrol Pinleri | A3 (CS), A2 (CD), A1 (WR), A0 (RD), A4 (RST) | Ekran grafik çizim verilerini yönetir. |
| Kilit Servosu | Dijital 13 | Şifre doğru olduğunda 90° dönerek fiziksel sürgüyü açar. |
Geliştirdiğimiz projenin tüm kütüphane bağlantılarını, matematiksel matris hesaplamalarını ve ekran koruyucu döngülerini içeren tam ve çalışır haldeki kaynak koduna aşağıdan ulaşabilirsiniz:
#include "TFTLCD.h"
#include "TouchScreen.h"
#include <EEPROM.h>
#include <Servo.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 (RGB565)
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define WHITE 0xFFFF
#define YELLOW 0xFFE0
#define CYAN 0x07FF
#define GRAY 0x7BEF
#define DARK_GRAY 0x31A6
TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);
// Servo Motor Yapılandırması
Servo kilitServosu;
#define SERVO_PIN 13 // Servo sinyal pini
// 5-Nokta Kalibrasyon Katsayıları (EEPROM adres: 0-24 arası kullanılır)
float tsA = 0.3117, tsB = 0.0, tsC = -46.75;
float tsD = 0.0, tsE = -0.39, tsF = 366.8;
struct CalibData {
byte magic; // Kalibrasyon geçerlilik imzası (0xCD)
float A; float B; float C;
float D; float E; float F;
};
// Şifre Kayıt Yapısı (EEPROM adres: 30'dan itibaren başlar)
#define PASSCODE_EEPROM_ADDR 30
struct PasscodeData {
byte magic; // Şifre geçerlilik imzası (0x55)
char code[5]; // 4 haneli şifre + null terminator
};
// Durum Makinesi (State Machine) Tanımları
enum SistemDurumu { KILITLI, ACILDI, ADMIN_MENUSU, KALIB };
SistemDurumu mevcutDurum = KILITLI;
// Çalışma Değişkenleri
String girilenSifre = "";
char kayitliSifre[5] = "1234"; // Varsayılan şifre
int hataliDenemeSayisi = 0;
unsigned long ekranZamanlayici = 0;
// Ekran Koruyucu (Hareketsizlik) Değişkenleri
unsigned long sonAktiviteZamani = 0;
bool ekranKapali = false;
// Tuş Takımı Matrisi (3x4)
char keys[4][3] = {
{'1', '2', '3'},
{'4', '5', '6'},
{'7', '8', '9'},
{'C', '0', 'E'} // C: Temizle, E: Onayla (Enter)
};
// Buton Yerleşim Ölçüleri
#define START_X 15
#define START_Y 120
#define BTN_W 65
#define BTN_H 40
#define GAP_X 12
#define GAP_Y 8
#define MINPRESSURE 150
#define MAXPRESSURE 1000
// Geliştirilmiş Güvenli Dokunmatik Okuma Fonksiyonu
TSPoint guvenliDokunmatikOku() {
// 1. Ekran pinlerindeki statik yükü (parazit akımı) tamamen boşaltmak için INPUT yapıyoruz
pinMode(XP, INPUT);
pinMode(XM, INPUT);
pinMode(YP, INPUT);
pinMode(YM, INPUT);
delayMicroseconds(150); // Statik yükün sönümlenmesi için bekliyoruz
// Dokunmatik panelden anlık ham verileri alıyoruz
TSPoint p = ts.getPoint();
// Ekran kontrol pinlerinin paylaşımlı olması sebebiyle çıkış ayarlarını yeniliyoruz
pinMode(XM, OUTPUT);
pinMode(YP, OUTPUT);
digitalWrite(XM, HIGH);
digitalWrite(YP, HIGH);
return p;
}
void setup(void) {
Serial.begin(9600);
// Servo motoru başlat ve kilitli konuma (0 derece) getir
kilitServosu.attach(SERVO_PIN);
kilitServosu.write(0);
tft.reset();
tft.initDisplay();
tft.setRotation(0); // Dikey Ekran Yönü (240x320)
// EEPROM'dan kalibrasyon ve şifre yükleme işlemleri
eepromYukle();
sifreYukle();
// İlk açılışta kalibrasyon yönetim ekranını başlat
kalibrasyonYonetimi();
// Hareketsizlik zamanlayıcısını başlatıyoruz
sonAktiviteZamani = millis();
// Kilit ekranını çizdir
kilitEkraniCiz();
}
void loop() {
// 10 saniye boyunca hiçbir dokunma olmazsa ekranı karartarak kapatıyoruz
if (!ekranKapali && (millis() - sonAktiviteZamani > 10000)) {
ekranKapali = true;
tft.fillScreen(BLACK);
}
// Yenilenen güvenli okuma mekanizması
TSPoint p = guvenliDokunmatikOku();
if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {
// Kalibre edilmiş 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);
// Her dokunma algılandığında hareketsizlik zamanlayıcısını sıfırlıyoruz
sonAktiviteZamani = millis();
// Eğer ekran kapalıysa, ilk dokunuşta sadece ekranı açıyoruz (Buton tetiklenmez)
if (ekranKapali) {
ekranKapali = false;
dokunmaBirakilanaKadarBekle(); // Ekranı açan dokunuşun yanlış tuşlara basmasını engelliyoruz
// Kaldığı duruma göre ekranı yeniden çizdir
if (mevcutDurum == KILITLI) {
kilitEkraniCiz();
} else if (mevcutDurum == ACILDI) {
erisimVerildi();
} else if (mevcutDurum == ADMIN_MENUSU) {
adminMenusuCiz();
}
return; // Bu döngü adımını burada sonlandır, basılan tuşu işleme alma
}
switch (mevcutDurum) {
case KILITLI:
kilitEkraniDokunmaYonet(x, y);
break;
case ACILDI:
acildiEkraniDokunmaYonet(x, y);
break;
case ADMIN_MENUSU:
adminEkraniDokunmaYonet(x, y);
break;
case KALIB:
break;
}
}
// Kapı açıldıktan 5 saniye sonra otomatik olarak kilitleme kontrolü
if (mevcutDurum == ACILDI && millis() - ekranZamanlayici > 5000) {
kilitServosu.write(0); // Kilidi kapat
kilitEkraniCiz();
sonAktiviteZamani = millis(); // Otomatik kilitlenme sonrasında zamanlayıcıyı güncelliyoruz
}
}
// --- ARAYÜZ ÇİZİM FONKSİYONLARI ---
void kilitEkraniCiz() {
mevcutDurum = KILITLI;
girilenSifre = "";
tft.fillScreen(BLACK);
// Üst Mavi Şerit
tft.fillRect(0, 2, tft.width(), 38, BLUE);
tft.drawString(35, 14, "GUVENLIK SISTEMI", WHITE, 2);
// Şifre Gösterge Kutusu
tft.drawRect(15, 55, 210, 50, BLUE);
gostergeGuncelle();
// Tuş Takımını Çiz (3x4)
for (int satir = 0; satir < 4; satir++) {
for (int sutun = 0; sutun < 3; sutun++) {
int btnX = START_X + (sutun * (BTN_W + GAP_X));
int btnY = START_Y + (satir * (BTN_H + GAP_Y));
char tusVal = keys[satir][sutun];
uint16_t btnColor = DARK_GRAY;
if (tusVal == 'C') btnColor = RED;
else if (tusVal == 'E') btnColor = GREEN;
tft.fillRect(btnX, btnY, BTN_W, BTN_H, btnColor);
tft.drawRect(btnX, btnY, BTN_W, BTN_H, WHITE);
uint16_t textColor = (tusVal == 'E') ? BLACK : WHITE;
tft.drawString(btnX + 25, btnY + 12, String(tusVal).c_str(), textColor, 2);
}
}
}
void gostergeGuncelle() {
tft.fillRect(16, 56, 208, 48, BLACK);
String maskeliSifre = "";
for (int i = 0; i < girilenSifre.length(); i++) {
maskeliSifre += "* ";
}
for (int i = girilenSifre.length(); i < 4; i++) {
maskeliSifre += "_ ";
}
tft.drawString(55, 70, maskeliSifre.c_str(), CYAN, 2);
}
void kilitEkraniDokunmaYonet(int x, int y) {
for (int satir = 0; satir < 4; satir++) {
for (int sutun = 0; sutun < 3; 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 tusVal = keys[satir][sutun];
// Basıldı Efekti
tft.fillRect(btnX, btnY, BTN_W, BTN_H, WHITE);
tft.drawString(btnX + 25, btnY + 12, String(tusVal).c_str(), BLACK, 2);
delay(150);
// Eski rengine döndür
uint16_t btnColor = DARK_GRAY;
if (tusVal == 'C') btnColor = RED;
else if (tusVal == 'E') btnColor = GREEN;
tft.fillRect(btnX, btnY, BTN_W, BTN_H, btnColor);
tft.drawRect(btnX, btnY, BTN_W, BTN_H, WHITE);
uint16_t textColor = (tusVal == 'E') ? BLACK : WHITE;
tft.drawString(btnX + 25, btnY + 12, String(tusVal).c_str(), textColor, 2);
// Tuş İşlemleri
if (tusVal >= '0' && tusVal <= '9') {
if (girilenSifre.length() < 4) {
girilenSifre += tusVal;
gostergeGuncelle();
}
}
else if (tusVal == 'C') {
girilenSifre = "";
gostergeGuncelle();
}
else if (tusVal == 'E') {
if (girilenSifre == String(kayitliSifre)) {
// ŞİFRE DOĞRU
erisimVerildi();
} else {
// ŞİFRE YANLIŞ
erisimReddedildi();
}
}
delay(150); // Debounce
}
}
}
}
void erisimVerildi() {
mevcutDurum = ACILDI;
hataliDenemeSayisi = 0;
ekranZamanlayici = millis();
tft.fillScreen(BLACK);
tft.fillRect(10, 40, 220, 100, GREEN);
tft.drawRect(10, 40, 220, 100, WHITE);
tft.drawString(30, 65, "ERISIM ONAYLANDI", BLACK, 2);
tft.drawString(55, 95, "KAPI ACILDI", BLACK, 2);
// "YÖNETİCİ MENÜSÜ" Butonu
tft.fillRect(15, 180, 210, 50, BLUE);
tft.drawRect(15, 180, 210, 50, WHITE);
tft.drawString(35, 196, "SIFREYI DEGISTIR", WHITE, 2);
// "KİLİTLE" Butonu
tft.fillRect(15, 245, 210, 50, RED);
tft.drawRect(15, 245, 210, 50, WHITE);
tft.drawString(75, 261, "KILITLE", WHITE, 2);
// Servoyu Açık Konuma Getir (90 derece)
kilitServosu.write(90);
}
void erisimReddedildi() {
hataliDenemeSayisi++;
tft.fillRect(16, 56, 208, 48, BLACK);
tft.drawString(30, 70, "HATALI SIFRE!", RED, 2);
girilenSifre = "";
delay(1500);
if (hataliDenemeSayisi >= 3) {
tft.fillScreen(BLACK);
tft.drawString(20, 120, "GIVENLIK KILIDI", RED, 2);
tft.drawString(20, 150, "30 SN BEKLEYIN!", RED, 2);
delay(30000); // 30 saniye cezalı bekleme
hataliDenemeSayisi = 0;
}
kilitEkraniCiz();
}
void acildiEkraniDokunmaYonet(int x, int y) {
// "ŞİFREYİ DEĞİŞTİR" Butonu (Yönetici Girişi)
if (x > 15 && x < 225 && y > 180 && y < 230) {
dokunmaBirakilanaKadarBekle();
adminMenusuCiz();
}
// "KİLİTLE" Butonu
else if (x > 15 && x < 225 && y > 245 && y < 295) {
dokunmaBirakilanaKadarBekle();
kilitServosu.write(0); // Kilitle
kilitEkraniCiz();
}
}
void adminMenusuCiz() {
mevcutDurum = ADMIN_MENUSU;
girilenSifre = "";
tft.fillScreen(BLACK);
tft.fillRect(0, 2, tft.width(), 38, BLUE);
tft.drawString(45, 14, "YONETICI MENUSU", WHITE, 2);
tft.drawString(15, 50, "Yeni Sifre Belirleyin:", WHITE, 1.5);
tft.drawRect(15, 65, 210, 45, BLUE);
gostergeGuncelle();
// Tuş takımını tekrar çiz (3x4)
for (int satir = 0; satir < 4; satir++) {
for (int sutun = 0; sutun < 3; sutun++) {
int btnX = START_X + (sutun * (BTN_W + GAP_X));
int btnY = START_Y + (satir * (BTN_H + GAP_Y));
char tusVal = keys[satir][sutun];
uint16_t btnColor = DARK_GRAY;
if (tusVal == 'C') btnColor = RED;
else if (tusVal == 'E') btnColor = GREEN;
tft.fillRect(btnX, btnY, BTN_W, BTN_H, btnColor);
tft.drawRect(btnX, btnY, BTN_W, BTN_H, WHITE);
uint16_t textColor = (tusVal == 'E') ? BLACK : WHITE;
tft.drawString(btnX + 25, btnY + 12, String(tusVal).c_str(), textColor, 2);
}
}
}
void adminEkraniDokunmaYonet(int x, int y) {
for (int satir = 0; satir < 4; satir++) {
for (int sutun = 0; sutun < 3; 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 tusVal = keys[satir][sutun];
// Basıldı efekti
tft.fillRect(btnX, btnY, BTN_W, BTN_H, WHITE);
tft.drawString(btnX + 25, btnY + 12, String(tusVal).c_str(), BLACK, 2);
delay(150);
uint16_t btnColor = DARK_GRAY;
if (tusVal == 'C') btnColor = RED;
else if (tusVal == 'E') btnColor = GREEN;
tft.fillRect(btnX, btnY, BTN_W, BTN_H, btnColor);
tft.drawRect(btnX, btnY, BTN_W, BTN_H, WHITE);
uint16_t textColor = (tusVal == 'E') ? BLACK : WHITE;
tft.drawString(btnX + 25, btnY + 12, String(tusVal).c_str(), textColor, 2);
if (tusVal >= '0' && tusVal <= '9') {
if (girilenSifre.length() < 4) {
girilenSifre += tusVal;
// Admin ekranında şifre girilirken gizlemeden gösterelim ki hatayı görsün
tft.fillRect(16, 66, 208, 43, BLACK);
tft.drawString(75, 80, girilenSifre.c_str(), YELLOW, 2);
}
}
else if (tusVal == 'C') {
girilenSifre = "";
tft.fillRect(16, 66, 208, 43, BLACK);
}
else if (tusVal == 'E') {
if (girilenSifre.length() == 4) {
// Şifreyi Kaydet
sifreKaydet(girilenSifre);
tft.fillScreen(BLACK);
tft.drawString(20, 120, "SIFRE BASARIYLA", GREEN, 2);
tft.drawString(20, 150, "KAYDEDILDI!", GREEN, 2);
delay(2000);
kilitServosu.write(0); // Kapıyı kilitle
kilitEkraniCiz();
} else {
tft.fillRect(16, 66, 208, 43, BLACK);
tft.drawString(20, 80, "4 HANE OLMALI!", RED, 2);
delay(1500);
girilenSifre = "";
tft.fillRect(16, 66, 208, 43, BLACK);
}
}
delay(150);
}
}
}
}
// --- EEPROM VE KALİBRASYON YÖNETİMİ ---
void sifreYukle() {
PasscodeData pData;
EEPROM.get(PASSCODE_EEPROM_ADDR, pData);
if (pData.magic == 0x55) {
strcpy(kayitliSifre, pData.code);
Serial.println("Kayıtlı Şifre EEPROM'dan Yüklendi ! ");
} else {
Serial.println("Kayıtlı şifre bulunamadı. Varsayılan şifre etkin !");
}
}
void sifreKaydet(String yeniSifre) {
PasscodeData pData;
pData.magic = 0x55;
yeniSifre.toCharArray(pData.code, 5);
EEPROM.put(PASSCODE_EEPROM_ADDR, pData);
strcpy(kayitliSifre, pData.code);
Serial.print("Yeni Şifre EEPROM'a Yazıldı: ");
Serial.println(kayitliSifre);
}
void kalibrasyonYonetimi() {
tft.fillScreen(BLACK);
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);
// KALIBRE ET Butonu
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
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);
}
// Güvenli dokunmatik okuma revizyonu
TSPoint p = guvenliDokunmatikOku();
if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {
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);
if (tx > 15 && tx < 225 && ty > 140 && ty < 185) {
dokunmaBirakilanaKadarBekle();
kalibrasyonYap5Nokta();
secimYapildi = true;
break;
}
if (tx > 15 && tx < 225 && ty > 205 && ty < 250) {
dokunmaBirakilanaKadarBekle();
eepromYukle();
secimYapildi = true;
break;
}
}
delay(50);
}
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);
long tX[5] = {30, 210, 30, 210, 120};
long tY[5] = {40, 40, 280, 280, 160};
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]);
long rawXSum = 0;
long rawYSum = 0;
int basariliOkuma = 0;
// Güvenli ilk algılama
while (true) {
TSPoint p = guvenliDokunmatikOku();
if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {
delay(100);
break;
}
}
// Gürültüyü süzmek için ardışık 16 örnek toplama
for (int numSamples = 0; numSamples < 16; numSamples++) {
TSPoint p = guvenliDokunmatikOku();
if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {
rawXSum += p.x;
rawYSum += p.y;
basariliOkuma++;
}
delay(15);
}
// Olası bir sıfıra bölünme hatasını engelleme
if (basariliOkuma > 0) {
rX[i] = rawXSum / basariliOkuma;
rY[i] = rawYSum / basariliOkuma;
} else {
i--; // Ölçüm başarısız, adımı tekrarla
continue;
}
dokunmaBirakilanaKadarBekle();
}
float nA, nB, nC, nD, nE, nF;
if (calculateLeastSquares(rX, rY, tX, tY, nA, nB, nC, nD, nE, nF)) {
dogrulamaVeTestEkrani(nA, nB, nC, nD, nE, nF);
} else {
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;
}
double a = Sxx; double b = Sxy; double c = Sx;
double e = Syy; double f = Sy; double k = 5.0;
double det = a * (e * k - f * f) - b * (b * k - c * f) + c * (b * f - c * e);
if (abs(det) < 0.0001) {
return false;
}
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;
outA = (m00 * Vx0 + m01 * Vx1 + m02 * Vx2) / det;
outB = (m01 * Vx0 + m11 * Vx1 + m12 * Vx2) / det;
outC = (m02 * Vx0 + m12 * Vx1 + m22 * Vx2) / det;
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);
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);
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) {
// Güvenli okuma
TSPoint p = guvenliDokunmatikOku();
if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {
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);
if (testX > 8 && testX < 228 && testY > 8 && testY < 220) {
tft.fillCircle(testX, testY, 2, GREEN);
}
if (testX > 10 && testX < 115 && testY > 240 && testY < 290) {
dokunmaBirakilanaKadarBekle();
tsA = nA; tsB = nB; tsC = nC;
tsD = nD; tsE = nE; tsF = nF;
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;
}
if (testX > 125 && testX < 230 && testY > 240 && testY < 290) {
dokunmaBirakilanaKadarBekle();
kalibrasyonYap5Nokta();
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 {
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 = guvenliDokunmatikOku();
if (p.z < MINPRESSURE || p.z > MAXPRESSURE) {
basili = false;
}
delay(30);
}
delay(100);
}
Henüz yorum yapılmamış. İlk yorumu siz yapın!