Merhaba arkadaşlar. Bu uygulamamda yine STM32 ile ile touch paneller üzerine bir çalışma yapıp, basitçe paint uygulaması yapmaya çalıştım MCBSTM32C board üzerinde bulunan TFT modülü kullandım. Bu LCD üzerinde dokunmatik ekran sürücüsü STMPE811 çipi kullanılmış. Bu çipin driver programı için ben fazla birşey yazmadım açıkçası. Keil ile birlikte gelen örnek kodların içerisinde bulunmakta. Sadece ben kendime göre biraz düzenledim.
STMPE811 in Datasheetine Buradan ulaşabilirsiniz.
Bu enteğre bayağı karışık. Kullanıma hazır hale getirmek için birçok register üzerinde işlem yapmak gerekiyor.
Bu ayarların hepsini örnek kodlar içerisinden hazır aldım ben. Sonradan bazı registerler üzerinde oynamalar yaparak sensörün çalışmasını yaptığım uygulamaya uygun hale getirdim.. Bu sebeble Register ve görevlerini uzun uzadıya anlatmayacağım. Datasheet te gerekli açıklamalar mevcut zaten.
Touch Panel ayarlamaları aşağıdaki gibi olacaktır.
unsigned int i; I2C_Setup(); /* I2C Donanimi hazirlaniyor */ I2C_putbyte (CHIP_ADDR, TSC_CTRL, 0x03); /* X, Y Çalisma Modu Aktif */ I2C_putbyte (CHIP_ADDR, SYS_CTRL1, 0x02); /* Touch Çipi Resetleniyor */ for (i = 0; i < 180000; i++); /* */ I2C_putbyte (CHIP_ADDR, SYS_CTRL2, 0x0C); /* Touch Screen ve ADC Enable */ I2C_putbyte (CHIP_ADDR, INT_EN, 0x07); /* Touch Detect ve FIFO aktif */ I2C_putbyte (CHIP_ADDR, ADC_CTRL1, 0x69); /* Set sample time , 12-bit mode */ for (i = 0; i < 36000; i++); /* */ I2C_putbyte (CHIP_ADDR, ADC_CTRL2, 0x01); /* ADC frekansi 3.25 MHz */ I2C_putbyte (CHIP_ADDR, TSC_CFG, 0x62); /* TSC_CFG Registeri ayarlaniyor */ I2C_putbyte (CHIP_ADDR, FIFO_TH, 0x01); /* Threshold for FIFO */ I2C_putbyte (CHIP_ADDR, FIFO_STA, 0x01); /* FIFO Reset */ I2C_putbyte (CHIP_ADDR, FIFO_STA, 0x00); /* */ I2C_putbyte (CHIP_ADDR, TSC_FRACTION_Z, 0x07); /* Fraction z */ I2C_putbyte (CHIP_ADDR, TSC_I_DRIVE, 0x01); /* Sürüs Modu 50 mA */ I2C_putbyte (CHIP_ADDR, TSC_CTRL, 0x01); /* Dokunmatik Panel Aktif */ I2C_putbyte (CHIP_ADDR, INT_STA, 0xFF); /* Kesme flagi temizleniyor */ I2C_putbyte (CHIP_ADDR, INT_CTRL, 0x01); /* Tüm kesmeler aktif */
Burada kullandığım I2C kütüphanesi bir önceki accelerometer uygulamamdaki ile aynıdır. Bu donanım üzerinde hiçbir değişiklik yapmadım.
STMPE811 in intterrup çıkışı CS pinine bağlanmış. Ben dokumayı algılamak için interrupt çıkışlarını kullanmadım. Sürekli olarak TSC_CNTL Registerinin 7. Bitini kontrol ettim. Ekranda herhangi bir dokunma algılandığı zaman bu bit 1 olamaktadır. Bu sayede dokunmayı farkedebiliyorum.
Bu işi yapmak üzere ufak bir fonksiyon hazırladım.
u8 TSC_TouchDet (void) { u8 Temp; u8 Touch = 0; Temp=Touch_Read(TSC_CTRL,1); if (Temp & (1 << 7)) { Touch = 1; } else { Touch = 0; } return Touch; }
Dokunma varsa Bu fonksiyon 1 ile geri dönüyor. Dokunma algılandıktan sonra hemen X,Y ve Z kordinat bilgilerini okuyorum. Sensör kullanımı bu şekilde. Bundan sonraki iş gelen kordinat bilgilerini analiz etmek.
Aslında internette izlediğim videolarda birde dokunmatik panel kalibrasyonu yapıldığını gördüm. Bunun için ilk başta ekranın birbirinden uzak 3 veya 4 noktasına bir işaret koyulup kullanıcının sırayla bu noktalara dokunması bekleniyor. Kullanıcı tüm noktalara dokununca elde edilen kordinat bilgileri bazı hesaplardan sonra ekranı kalibre etmekte kullanılıyor.
İnternette birkaç sitede nasıl yapıldığını anlatmışlardı fakat çok karmaşık matematiksel hesaplamaları vardı. Açıkçası bu matematiksel işlemleride anlamayınca bende kalibrasyon olmadan daha basit bir yol ile çözdüm meseleyi
Dokunmatik panelden X ve Y eksen bilgileri yaklaşık olarak 200 ile 3900 arasında geliyor. Bizim amacımız örneğin X ekseni için 3900 gibi bir değer geldiğinde elimzide 320 değeri, 200 geldiğinde ise 0 değeri olsun. Bunu yapmak için X ve Y eksenleri için birer katsayı belirleyip okuduğum kordinat bilgilerini sürekli bu değerle çarparak bana lazım olan değerleri elde etmiş oldum. Sonuç olarak elde ettiğim değerler çok küsüratlı oluyordu. Birde yuvarlamak gerekiyor bu sayıları.
Yaptığım bu işlemleri burada görebilirsiniz.
void Touch_Read_Data(void) { for(i=0;i<3;i++) { tch_x=Touch_Read(0x4F,2); // X Eksen Bilgileri okunuyor tch_y=Touch_Read(0x4D,2); // Y Eksen Bilgileri okunuyor tch_z=Touch_Read(0x51,1); // Z Eksen Bilgileri okunuyor } if(tch_x>touch_max_value) tch_x=3900; // X ekseni Max Degerden büyükse X degerini 3900 Yap if(tch_x<touch_min_value) tch_x=200; // Y ekseni Min Degerden kücükse X degerini 200 yap if(tch_y>touch_max_value) tch_y=3900; if(tch_y<touch_min_value) tch_y=200; tch_xd=floor((tch_x-200) * xmult); // Sonuç degeri Yuvarlaniyor tch_yd=(240-floor((tch_y-200) * ymult)); }
Şimdi biraz yaptığım uygulamadan bahsedeyim.
Yaptığım bu uygulamada kısaca okuduğum kordinat bilgilerine göre ekranda o kordinata karşılık gelen kordinata nokta koydum. Araya birazda görsellik katarak paint benzeri bir uygulama yapmış oldum.
Yaptığım uygulamanın Ekran görüntüsü Aşağıdaki şekildedir.
Arayüz Tasarımını MikroE firmasının geliştirmiş olduğu Visual TFT Programında yaptım. Programın görselliği çok güzel. Bazı özellikleri hoşuma gidiyor. Bunun dışında pekde bir numarası yok. Genel olarak MikroE ürünleri için tasarlandığından dolayı programın işlevleri hep kendi ürünlerine yönelik. Yoksa Aynı tasarımı diğer birçok programda yapabilirsiniz.
Tasarladığım arayüzde 7 adet buton var. Bu butonların 5 tanesi çizgi kalınlığını seçmenize yardımcı olur. Diğer iki butonda Clear butonu ekranı seçili olan renge boyar. Bir anlamda ekranı temizler.
Silgi butonu ise silgiyi aktif eder.
Ekranda gördüğünüz butonların hepsi resimlerden oluşmaktadır. Normalde basılı hali ve basılmamış hali olmak üzere her buton için iki adet resim bulunmaktadır. Butonlara dokunulduğu zaman basılmış efekti vermek için sadece resimler değiştirilir. İşin Bütün espirisi budur.
Şimdilik ben beyaz dahil 13 adet renk seçeneği ekledim. Butonları fazla küçültmek istemedim. Bu haliyle ideal olduğunu düşünüyorum.
Normalde Bu resimlerin hepsini 16bit 565(5bit R, 6 bit G, 5 bit B) formatında const array şeklinde diziye dökmek gerekiyor. Bu iş için birkaç program kullandım. Bazı programların ilginç bir şekilde renkleri karıştırdığını gördüm. Yani kırmızı çıkması gereken yerde mavi, mavi çıkması gereken yerlerde kırmızı çıktığını gördüm. En son aşağıdaki sitedeki programı buldum. Aralarından en düzgünü budur.
Sadece 565 değil birkaç resim formatını daha destekliyor.
Programı Buradan indirebilirsiniz.
Bu uygulamada karşılaştığım problemlerden bir taneside hafıza oldu. Aslında hiç hesaba katmamıştım. Normalde 16 bit 320X240 bir resim 150kb dan fazla tutuyor. Halbuki kullandığım STM32F107VC nin Flash hafızası sadece 256kb, Dolayısıyla ikinci bir 320×240 boyutunda resim ekleyemedim. Buna dikkat etmek gerekiyor. Hafıza bu işlerde çok büyük bir faktör.
Main içerisinde yazdığım program aşağıdaki gibidir. Bu konuda da birkaç noktaya değinmek isterim.
//////////////////////////////////////////////////////////////////////////////// // Author : [Ferhat YOL] / // Notice : Copyright (c) 2012 / // : All Rights Reserved / // Date : 01-04-2013 / // Version : 1.0.0 / // Board : MCBSTM32C / // MCU : STM32F107VC / // Notes : LCD Controller SPFD5408 / // : Touch Controller STMPE811 / //////////////////////////////////////////////////////////////////////////////// #include "stm32f107.h" #define xmult 0.0863 //Touch X Mult. #define ymult 0.0647 //Touch Y Mult. #define touch_max_value 3900 //Touch Max Value #define touch_min_value 200 //Touch Min Value /****************************Degiskenler*************************************/ char buf[10]; int i=0; unsigned int tch_x=0, tch_y=0, tch_z=0; unsigned int tch_xd=0, tch_yd=0; unsigned int tch_xd_=0, tch_yd_=0; unsigned int size=1,old_size=0; unsigned int Color=White; BOOL Touch_On=0,Touch_Clear=0,Touch_Erase=0; BOOL Touch_Size=0,Color_Select=0; /*******************************Resimler**************************************/ extern unsigned char Ana_Res[]; extern unsigned char erase_selected[]; extern unsigned char erase_not_selected[]; extern unsigned char clear_selected[]; extern unsigned char clear_not_selected[]; extern unsigned char Size5_Selected[]; extern unsigned char Size5_not_Selected[]; extern unsigned char Size4_Selected[]; extern unsigned char Size4_not_Selected[]; extern unsigned char Size3_Selected[]; extern unsigned char Size3_not_Selected[]; extern unsigned char Size2_Selected[]; extern unsigned char Size2_not_Selected[]; extern unsigned char Size1_Selected[]; extern unsigned char Size1_not_Selected[]; /*****************************Fonksiyonlar************************************/ void Erase_Touch_Detect (void); void Size_Touch_Detect (void); void Size_Select (u8 size,u8 old_size); void Touch_Read_Data (void); void Set_Color_Detect (void); int main() { SystemInit(); // Sistem Ayarlari yapiliyor.. initRS232(9600); // RS232 Ayarlamalari yapiliyor GLCD_Init(); // Grafik LCD Ayarlamalari Yapiliyor Touch_Init(); // Dokunmatik panel Ayarlamalari Yapiliyor. setOutMode(portE,0xFFFF); // PortE Çikis Yapildi /***************************************Giris****************************************/ //GLCD_Clear(White); GLCD_SetBackColor(White); GLCD_SetTextColor(Color); GLCD_Bitmap(0,0,320,240,Ana_Res); Size_Select(size,0); while(1){ if(TSC_TouchDet()){ output(portE,0xFF00); Touch_Read_Data(); // Kordinat Bilgilerini okunuyor if(tch_xd>28 && tch_xd<316 && tch_yd>26 && tch_yd<236) // Basilan Nokta Çizim Alani içerisinde ise.. { if((tch_xd!=tch_xd_) | (tch_yd!=tch_yd_)) { GLCD_Circle(tch_xd,tch_yd,size,1); tch_xd_=tch_xd;tch_yd_=tch_yd; } } if(!Touch_Clear) { if(tch_xd>2 && tch_xd<32 && tch_yd>2 && tch_yd<22) //Clear Butonun basilmissa { GLCD_Bitmap(2,2,30,20,clear_selected); Touch_Clear=1; } } Erase_Touch_Detect(); // Erase Butonu Olaylar, Size_Touch_Detect(); // Kalinlik Secim olaylari Set_Color_Detect(); // Renk Secim Olaylari }else{ // Dokunma Yoksa output(portE,0x0000); tch_x=0,tch_y=0,tch_z=0; tch_xd=0;tch_yd=0;tch_xd_=0;tch_yd=0; Touch_On=0;Touch_Size=0;Color_Select=0; if(Touch_Clear) // Eger Clear Butonuna basilmissa { GLCD_Bitmap(2,2,30,20,clear_not_selected); // Clear Not Selected Resmini Bas GLCD_ClearWorkArea(27,25,292,214,Color); // Calisma Alanini Temizle GLCD_SetWindow(27,25,291,213); // Eski Calisma Alani yükleniyor. Touch_Clear=0; } } } } void Erase_Touch_Detect(void) { if(!Touch_On) //Erase Butonuna basilirsa { if(tch_xd>2 && tch_xd<23 && tch_yd>27 && tch_yd<48) { if(Touch_Erase) { GLCD_Bitmap(3,27,20,20,erase_not_selected); GLCD_SetWindow(27,25,291,213); GLCD_SetTextColor(Color); Touch_Erase=0; } else { GLCD_Bitmap(3,27,20,20,erase_selected); GLCD_SetWindow(27,25,291,213); GLCD_SetTextColor(White); Touch_Erase=1; } Touch_On=1; } } } void Touch_Read_Data(void) { for(i=0;i<3;i++) { tch_x=Touch_Read(0x4F,2); // X Eksen Bilgileri okunuyor tch_y=Touch_Read(0x4D,2); // Y Eksen Bilgileri okunuyor tch_z=Touch_Read(0x51,1); // Z Eksen Bilgileri okunuyor } if(tch_x>touch_max_value) tch_x=3900; // X ekseni Max Degerden büyükse X degerini 3900 Yap if(tch_x<touch_min_value) tch_x=200; // Y ekseni Min Degerden kücükse X degerini 200 yap if(tch_y>touch_max_value) tch_y=3900; if(tch_y<touch_min_value) tch_y=200; tch_xd=floor((tch_x-200) * xmult); // Sonuç degeri Yuvarlaniyor tch_yd=(240-floor((tch_y-200) * ymult)); } void Size_Touch_Detect(void) { if(!Touch_Size) //Size Butonuna dokunulursa { if(size!=5 && tch_xd>2 && tch_xd<23 && tch_yd>48 && tch_yd<69) { old_size=size; size=5; Size_Select(size, old_size); } if(size!=4 && tch_xd>2 && tch_xd<23 && tch_yd>70 && tch_yd<91) { old_size=size; size=4; Size_Select(size, old_size); } if(size!=3 && tch_xd>2 && tch_xd<23 && tch_yd>92 && tch_yd<113) { old_size=size; size=3; Size_Select(size, old_size); } if(size!=2 && tch_xd>2 && tch_xd<23 && tch_yd>114 && tch_yd<135) { old_size=size; size=2; Size_Select(size, old_size); } if(size!=1 && tch_xd>2 && tch_xd<23 && tch_yd>136 && tch_yd<157) { old_size=size; size=1; Size_Select(size, old_size); } Touch_Size=1; } } void Size_Select(u8 size,u8 old_size) { switch (size) // Yeni Size Degeri Aktif yapiliyor. { case 1: GLCD_Bitmap(3,137,20,20, Size1_Selected); GLCD_SetWindow(27,25,291,213); break; case 2: GLCD_Bitmap(3,115,20,20, Size2_Selected); GLCD_SetWindow(27,25,291,213); break; case 3: GLCD_Bitmap(3,93 ,20,20, Size3_Selected); GLCD_SetWindow(27,25,291,213); break; case 4: GLCD_Bitmap(3,71 ,20,20, Size4_Selected); GLCD_SetWindow(27,25,291,213); break; case 5: GLCD_Bitmap(3,49 ,20,20, Size5_Selected); GLCD_SetWindow(27,25,291,213); break; } switch(old_size) // Eski Size Butonu Pasif Yapiliyor. { case 1: GLCD_Bitmap(3,137,20,20, Size1_not_Selected); GLCD_SetWindow(27,25,291,213); break; case 2: GLCD_Bitmap(3,115,20,20, Size2_not_Selected); GLCD_SetWindow(27,25,291,213); break; case 3: GLCD_Bitmap(3,93 ,20,20, Size3_not_Selected); GLCD_SetWindow(27,25,291,213); break; case 4: GLCD_Bitmap(3,71 ,20,20, Size4_not_Selected); GLCD_SetWindow(27,25,291,213); break; case 5: GLCD_Bitmap(3,49 ,20,20, Size5_not_Selected); GLCD_SetWindow(27,25,291,213); break; } } void Set_Color_Detect(void) { if(!Color_Select) { if(Color!=White) { if(tch_xd>34 && tch_xd<54 && tch_yd>2 && tch_yd<23) { Color=White; //Beyaz Renk Secildi GLCD_SetTextColor(Color); GLCD_Rectangle(4,219,22,237,1); GLCD_SetWindow(27,25,291,213); Color_Select=1; } } if(Color!=Red) { if(tch_xd>56 && tch_xd<77 && tch_yd>2 && tch_yd<23) { Color=Red; // GLCD_SetTextColor(Color); GLCD_Rectangle(4,219,22,237,1); GLCD_SetWindow(27,25,291,213); Color_Select=1; } } if(Color!=Orange) { if(tch_xd>78 && tch_xd<99 && tch_yd>2 && tch_yd<23) { Color=Orange; GLCD_SetTextColor(Color); GLCD_Rectangle(4,219,22,237,1); GLCD_SetWindow(27,25,291,213); Color_Select=1; } } if(Color!=Yellow) { if(tch_xd>100 && tch_xd<121 && tch_yd>2 && tch_yd<23) { Color=Yellow; GLCD_SetTextColor(Color); GLCD_Rectangle(4,219,22,237,1); GLCD_SetWindow(27,25,291,213); Color_Select=1; } } if(Color!=Green) { if(tch_xd>121 && tch_xd<143 && tch_yd>2 && tch_yd<23) { Color=Green; GLCD_SetTextColor(Color); GLCD_Rectangle(4,219,22,237,1); GLCD_SetWindow(27,25,291,213); Color_Select=1; } } if(Color!=Cyan) { if(tch_xd>144 && tch_xd<165 && tch_yd>2 && tch_yd<23) { Color=Cyan; GLCD_SetTextColor(Color); GLCD_Rectangle(4,219,22,237,1); GLCD_SetWindow(27,25,291,213); Color_Select=1; } } if(Color!=Blue) { if(tch_xd>166 && tch_xd<187 && tch_yd>2 && tch_yd<23) { Color=Blue; GLCD_SetTextColor(Color); GLCD_Rectangle(4,219,22,237,1); GLCD_SetWindow(27,25,291,213); Color_Select=1; } } if(Color!=Pink) { if(tch_xd>188 && tch_xd<209 && tch_yd>2 && tch_yd<23) { Color=Pink; GLCD_SetTextColor(Color); GLCD_Rectangle(4,219,22,237,1); GLCD_SetWindow(27,25,291,213); Color_Select=1; } } if(Color!=Purple) { if(tch_xd>210 && tch_xd<231 && tch_yd>2 && tch_yd<23) { Color=Purple; GLCD_SetTextColor(Color); GLCD_Rectangle(4,219,22,237,1); GLCD_SetWindow(27,25,291,213); Color_Select=1; } } if(Color!=Navy) { if(tch_xd>232 && tch_xd<253 && tch_yd>2 && tch_yd<23) { Color=Navy; GLCD_SetTextColor(Color); GLCD_Rectangle(4,219,22,237,1); GLCD_SetWindow(27,25,291,213); Color_Select=1; } } if(Color!=DarkGreen) { if(tch_xd>254 && tch_xd<275 && tch_yd>2 && tch_yd<23) { Color=DarkGreen; GLCD_SetTextColor(Color); GLCD_Rectangle(4,219,22,237,1); GLCD_SetWindow(27,25,291,213); Color_Select=1; } } if(Color!=Olive) { if(tch_xd>276 && tch_xd<297 && tch_yd>2 && tch_yd<23) { Color=Olive; GLCD_SetTextColor(Color); GLCD_Rectangle(4,219,22,237,1); GLCD_SetWindow(27,25,291,213); Color_Select=1; } } if(Color!=Black) { if(tch_xd>298 && tch_xd<319 && tch_yd>2 && tch_yd<23) { Color=Black; GLCD_SetTextColor(Color); GLCD_Rectangle(4,219,22,237,1); GLCD_SetWindow(27,25,291,213); Color_Select=1; } } if(Color_Select && Touch_Erase) { GLCD_Bitmap(3,27,20,20,erase_not_selected); GLCD_SetWindow(27,25,291,213); GLCD_SetTextColor(Color); Touch_Erase=0; } } }
Bu tip TFT lerde Ekrana bir data gönderileceği zaman ilk önce işlem yapılacak alan kadar bir pencere açılıp bu pencere içerisinde çalışılır. Biz Sol taraftaki butonlara her basışımızda butonların resmi değiştiği için butonun basıldığı noktaya bir pencere açılır içerisine buton basılır.
Bu işlemin ardından tekrardan çalışma alanımıza yeni bir pencere açmak gerekir. Çünkü En son buton bastığımız alana pencere açtığımız için biz bu alan dışında işlem yapmak istersek bile bu ekrana yansımaz. Bu yüzden her renk seçilişinde veya butonlara dokunulduktan sonra en son tekrar çalışma alanına pencere açılması gerekiyor.
Kodlarda bunu daha ayrıntılı bir şekilde görebilirsiniz.
Birde şunu gördüm. Burada kullanılan Touch paneller çok kalitesizmiş. Çok fazla yanlış kordinat veriyor. Eklediğim videodada görebilirsiniz. Bazen program ekranın rastgele bir noktasına nokta koyuyor. Biraz araştırınca bunun touch panel kalitesiyle ilgili olduğunu anladım. Yazılımsal olarak bunu önlemek için iyileştirme yaptım ama tam olarak kesemedim.
İnternetteki bu tür videolardada benzer durumu gördüm
Yaptığım uygulamanın vidosu
Bunlarda yaptığım birkaç sanat eseri 😀
Bu uygulamada yaşadığım hafıza problemlerinden sonra artık SD kart işini çözmem farz oldu bana. Bir sonraki çalışmam bu yönde olacak.
İyi çalışmalar.
Şifre-Pass: 320volt.com
Yayım tarihi: 2013/06/21 Etiketler: arm paint, arm projeleri, arm tft, stm32 paint, stm32 tft
güzel bir uygulama hemde eğlenceli elinize sağlık teşekkürler bende ufaktan başladım 🙂
hocam bende de bu STM setten var. Bendeki F103 RBT dokunmatik panelli. Fakt bu keil de program yazmak biraz sıkıntılı gibi. Çok fazla Library dosyası var hangisini nereye ekliycez keşke onuda bi yazsaydınız. Birde proje çok güzel elinize sağlık ama ekte hex dosyası yok oda olsaydı iyi olurdu kendimizinkine atıp bakardık çalışıyormu diye. keilde derleme çalışıyorum hata veriyor nedense. Zaten Keil deneme sürümü kısıtlama yapıyor. Bu işi acaba CCS de yapma şansımız yokmu, saygılar iyi çalışmalar